自定义cas客户端核心过滤器AuthenticationFilter
关于cas客户端的基本配置这里就不多说了,不清楚的可以参考上一篇博文:配置简单cas客户端。这里是关于cas客户端实现动态配置认证需要开发说明。
往往业务系统中有些模块或功能是可以不需要登录就可以访问的,但是添加了cas客户端之后,通过cas客户端filter中的url-pattern来设置需要过滤的url,有时根本无法满足实际业务的需求,这里笔者就通过对cas客户端中源码的阅读,和对认证流程的理解,对cas客户端做了些改动,来实现动态配置cas客户端认证范围。
下面是cas认证的核心配置,其中AuthenticationFilter过滤器为cas客户端核心过滤,下面的url-pattern是配置需要过滤的url,如果我们能编写该过滤器,我们就可以实现动态配置cas客户端的过滤url了。
- <!-- cas统一认证 -->
- <filter>
- <filter-name>CASFilter</filter-name>
- <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
- <init-param>
- <param-name>casServerLoginUrl</param-name>
- <param-value>http://localhost:8080/casServer3/login</param-value>
- </init-param>
- <init-param>
- <param-name>serverName</param-name>
- <param-value>http://localhost:8080</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CASFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter>
- <filter-name>CAS Validation Filter</filter-name>
- <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
- <init-param>
- <param-name>casServerUrlPrefix</param-name>
- <param-value>http://localhost:8080/casServer3</param-value>
- </init-param>
- <init-param>
- <param-name>serverName</param-name>
- <param-value>http://localhost:8080</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CAS Validation Filter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
思路:将配置中指向的核心过滤器,指向自己定义的过滤器,将源码中核心过滤器AuthenticationFilter的代码复制拷贝到该自定义过滤器中,然后在该过滤器中添加自己的过滤规则。
步骤:
1.配置并启动cas服务端,具体配置可以参考博文:搭建简单的cas认证服务
2.新建一个web项目,然后添加cas客户端配置,具体配置可以参考博文:配置简单cas客户端
3.导入cas客户端核心jar的源码到该web项目中,源码在cas客户端下载zip包中就有,一般为cas-client-core文件夹
4.在项目的src中新建类AuthenticationFilter,继承org.jasig.cas.client.util.AbstractCasFilter,打开web.xml文件,找到找到cas核心过滤器的配置项CASFilter,Ctrl+左键,点击进入org.jasig.cas.client.authentication.AuthenticationFilter类中,复制类里面的全部代码到自定义的AuthenticationFilter类中。修改web.xml中cas核心过滤器配置项CASFilter中的配置,将filter-class指向刚才自定义的AuthenticationFilter类,同时在该过滤器中添加<init-param>配置。如下
- <filter>
- <filter-name>CASFilter</filter-name>
- <filter-class>com.supre.filter.AuthenticationFilter</filter-class>
- <init-param>
- <param-name>casServerLoginUrl</param-name>
- <param-value>http://localhost:8080/casServer3/login</param-value>
- </init-param>
- <init-param>
- <param-name>serverName</param-name>
- <param-value>http://localhost:8080</param-value>
- </init-param>
- <init-param>
- <param-name>excludePaths</param-name>
- <param-value>.*[/,\]rest[/,\].*</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CASFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
说明:
1其中param-name为参数名,这个在过滤器初始化中需要根据该名字来取param-value中的值
2其中param-value的值可以根据需要在filter中制定自己的规则,笔者这里是正则表达式
5.在自定义的AuthenticationFilter中添加自己的代码,来实现认证范围的控制,代码如下:
- package com.supre.filter;
- import java.io.IOException;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
- import org.jasig.cas.client.authentication.GatewayResolver;
- import org.jasig.cas.client.util.AbstractCasFilter;
- import org.jasig.cas.client.util.CommonUtils;
- import org.jasig.cas.client.validation.Assertion;
- /**
- * 为了方便控制filter,自定义了统一认证过滤器AuthenticationFilter
- * @author Administrator
- *
- */
- public class AuthenticationFilter extends AbstractCasFilter{
- /**
- * The URL to the CAS Server login.
- */
- private String casServerLoginUrl;
- /**
- * Whether to send the renew request or not.
- */
- private boolean renew = false;
- /**
- * Whether to send the gateway request or not.
- */
- private boolean gateway = false;
- /**
- * 添加属性,这里用来存放不过滤地址正则表达式,可以根据自己需求定制---1
- */
- private String excludePaths;
- private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
- protected void initInternal(final FilterConfig filterConfig) throws ServletException {
- if (!isIgnoreInitConfiguration()) {
- super.initInternal(filterConfig);
- setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
- log.trace("Loaded CasServerLoginUrl parameter: " + this.casServerLoginUrl);
- setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
- log.trace("Loaded renew parameter: " + this.renew);
- setGateway(parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
- log.trace("Loaded gateway parameter: " + this.gateway);
- final String gatewayStorageClass = getPropertyFromInitParams(filterConfig, "gatewayStorageClass", null);
- if (gatewayStorageClass != null) {
- try {
- this.gatewayStorage = (GatewayResolver) Class.forName(gatewayStorageClass).newInstance();
- } catch (final Exception e) {
- log.error(e,e);
- throw new ServletException(e);
- }
- }
- //自定义添加代码,用来读取web配置文件中excludes属性值 ---2
- excludePaths = getPropertyFromInitParams(filterConfig, "excludePaths", null);//filterConfig.getInitParameter("excludePaths");
- excludePaths = excludePaths.trim();
- }
- }
- public void init() {
- super.init();
- CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
- }
- // url判断逻辑,这里大家可以根据自己需要来制订规则
- private boolean isExclude(String uri){
- boolean isInWhiteList = false;
- if(excludePaths!=null&& uri!=null){
- isInWhiteList = uri.matches(excludePaths);
- }
- return isInWhiteList;
- }
- public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
- final HttpServletRequest request = (HttpServletRequest) servletRequest;
- final HttpServletResponse response = (HttpServletResponse) servletResponse;
- final HttpSession session = request.getSession(false);
- final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
- // 该判断是自定义的对符合条件的url进行通过处理 ---3
- if(isExclude(request.getRequestURI())){
- filterChain.doFilter(request, response);
- return;
- }
- if (assertion != null) {
- filterChain.doFilter(request, response);
- return;
- }
- final String serviceUrl = constructServiceUrl(request, response);
- final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
- final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
- if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
- filterChain.doFilter(request, response);
- return;
- }
- final String modifiedServiceUrl;
- log.debug("no ticket and no assertion found");
- if (this.gateway) {
- log.debug("setting gateway attribute in session");
- modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
- } else {
- modifiedServiceUrl = serviceUrl;
- }
- if (log.isDebugEnabled()) {
- log.debug("Constructed service url: " + modifiedServiceUrl);
- }
- final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
- if (log.isDebugEnabled()) {
- log.debug("redirecting to "" + urlToRedirectTo + """);
- }
- response.sendRedirect(urlToRedirectTo);
- }
- public final void setRenew(final boolean renew) {
- this.renew = renew;
- }
- public final void setGateway(final boolean gateway) {
- this.gateway = gateway;
- }
- public final void setCasServerLoginUrl(final String casServerLoginUrl) {
- this.casServerLoginUrl = casServerLoginUrl;
- }
- public final void setGatewayStorage(final GatewayResolver gatewayStorage) {
- this.gatewayStorage = gatewayStorage;
- }
- }
说明:上面的例子笔者是想在web中配置不需要认证的url,通过正则表达式来判断,这里相关的规则可以根据自己需要来编写。
6.到这里就基本完成了,根据自己定义的规则来做测试,大家可以在项目中创建多个jsp或html文件,放在不同目录下(部分设计为通过,部分设计为不通过),然后在浏览器中直接访问这些文件,看是否被拦截而跳到认证见面,通过根据自己定义的规则判断修改是否成功。