背景:因为系统的庞大,所以将不同模块的系统放在不通的model模块中,这样在开发中可以一定程度上体现解耦的思想,不同模块之间的登录采用的是cas进行单点登录进行管理;但是开发过程中遇到一个问题,就是cas单点登录时,配置的过滤器是过滤所有的url请求的,及所有的请求url必须cas登录后才可以进行访问,但是有些url请求不需要登录的,比如注册请求url,这时我们就需要进行修改cas的过滤机制,但是在网上众多方法都是从新实现cas的AuthenticationFilter过滤器,然后进行重写过滤方法;这种方法较为复杂,还有一种方法cas其实提供了过滤url请求不拦截的配置,详情见下:(思想来源:https://blog.csdn.net/eguid_1/article/details/73611781)
环境:cas-server-webapp-4.1.2(注意版本,cas不同版本之间差距较大)
正文
在配置cas登录的模块下的web.xml文件中找到(不是cas的web.xml)如下配置:
<!-- 该过滤器负责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://192.168.4.195:8080/cas/login</param-value>
<!--这里的server是服务端的IP -->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://192.168.4.195:8080</param-value>
</init-param>
<init-param>
<description>不拦截的请求</description>
<param-name>ignorePattern</param-name>
<param-value>/test.html|/views/test/test.html|/lib/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
上边代码块中关键代码如下:
<init-param>
<description>不拦截的请求</description>
<param-name>ignorePattern</param-name>
<param-value>/test.html|/views/test/test.html|/lib/*</param-value>
</init-param>
就是配置cas忽略掉的请求,其中,标签中的值可以采用精准匹配忽略掉的请求,也可以使用正则的方式进行过滤忽略的请求,例如
<init-param>
<description>不拦截的请求</description>
<param-name>ignorePattern</param-name>
<param-value>/test*|/views/test/*|/lib/*</param-value>
</init-param>
配置如上后,需要注意的是,检查下自己配置的 用于将通过CAS认证的用户信息放入当前应用的上下文环境的过滤器,也是需要配置忽略掉的请求的,配置在web.xml文件中,如下:
<filter>
<filter-name>AutoSetUserFromCASFilter</filter-name>
<filter-class>com.hsnn.medstgmini.filter.AutoSetUserFromCASFilter</filter-class>
<init-param>
<--需要忽略的url,多个采用';'隔开-->
<param-name>noLoginPaths</param-name>
<param-value>test.html</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AutoSetUserFromCASFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
AutoSetUserFromCASFilter过滤器中的配置如下:
package com.hsnn.medstgmini.filter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import javax.servlet.Filter;
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.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.jasig.cas.client.util.AssertionHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.hsnn.medstgmini.Constants;
import com.hsnn.medstgmini.base.sys.model.SysUser;
import com.hsnn.medstgmini.base.sys.service.SysUserManager;
public class AutoSetUserFromCASFilter implements Filter {
private static final Logger log = Logger.getLogger(AutoSetUserFromCASFilter.class);
private String excludedPages;//web.xml中配置的过滤掉的请求
private String[] excludedPageArray;//请求截取后的结果
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(true);
//进行判断当前请求是否在忽略过滤的url的范围内,如果在,则不需要过滤,否则过滤
if(excludedPageArray!=null){
for (int i = 0; i < excludedPageArray.length; i++) {
if(excludedPageArray[i]==null || "".equals(excludedPageArray[i]))continue;
if(httpRequest.getRequestURI().indexOf(excludedPageArray[i])!=-1 ){
chain.doFilter(request, response);
return;
}
}
}
//实现其他的业务逻辑及判断
// 如session中已经存在用户信息,则不再从Redis Server中加载
if (session.getAttribute(Constants.USERINFO) != null) {
chain.doFilter(request, response);
return;
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(httpRequest.getSession().getServletContext());
SysUserManager sysUserManager = (SysUserManager) wac.getBean("sysUserManagerImpl");
// 从CAS中获取登录用户名
String userName = AssertionHolder.getAssertion().getPrincipal().getName();
SysUser user = sysUserManager.getUserByUsername(userName);
user.setLoginIp(request.getRemoteAddr());//获取客户ip地址
sysUserManager.updateLoginInfo(user);//修改登录iP和登录时间
log.info("It's ok to get 'SysUser Object' from medstgmini_std.service:" + user);
session.setAttribute(Constants.USERINFO, user);
chain.doFilter(request, response);
}
private void outputErrorInfo(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String errorMsg) throws IOException {
HttpSession session = httpRequest.getSession(true);
String header = httpRequest.getHeader("x-requested-with");
String ctx = session.getServletContext().getContextPath();
PrintWriter pw = httpResponse.getWriter();
pw.write(errorMsg);
pw.flush();
pw.close();
return;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//初始化时进行读取web.xml中配置的忽略url值,然后根据指定字符进行字符分割
excludedPages = filterConfig.getInitParameter("noLoginPaths");
if (StringUtils.isNotEmpty(excludedPages)) {
excludedPageArray = excludedPages.split(";");
}
return;
}
@Override
public void destroy() {
}
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
//序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
}
return null;
}
public static Object unserialize(byte[] bytes) {
ByteArrayInputStream bais = null;
try {
//反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
}
return null;
}
}
到这里配置完成,可以实现我们的需求进行忽略掉我们配置的请求了;但是知其然也要知其所以然,下边是跟着cas-client的源码进行分析:
在cas-client的AuthenticationFilter的初始化方法中,有提到ignorePattern (忽略正则),及cas过滤器在初始化的时候已经为我们提供了忽略正则的设置,so我们不需要大费周章的去重写cas的过滤器,而是可以通过查看源码的方式获取更简单更效率的做法;
protected void initInternal(FilterConfig filterConfig) throws ServletException {
if (!this.isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
this.setCasServerLoginUrl(this.getPropertyFromInitParams(filterConfig, "casServerLoginUrl", (String)null));
this.logger.trace("Loaded CasServerLoginUrl parameter: {}", this.casServerLoginUrl);
this.setRenew(this.parseBoolean(this.getPropertyFromInitParams(filterConfig, "renew", "false")));
this.logger.trace("Loaded renew parameter: {}", this.renew);
this.setGateway(this.parseBoolean(this.getPropertyFromInitParams(filterConfig, "gateway", "false")));
this.logger.trace("Loaded gateway parameter: {}", this.gateway);
String ignorePattern = this.getPropertyFromInitParams(filterConfig, "ignorePattern", (String)null);
this.logger.trace("Loaded ignorePattern parameter: {}", ignorePattern);
String ignoreUrlPatternType = this.getPropertyFromInitParams(filterConfig, "ignoreUrlPatternType", "REGEX");
this.logger.trace("Loaded ignoreUrlPatternType parameter: {}", ignoreUrlPatternType);
if (ignorePattern != null) {
Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = (Class)PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
if (ignoreUrlMatcherClass != null) {
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy)ReflectUtils.newInstance(ignoreUrlMatcherClass.getName(), new Object[0]);
} else {
try {
this.logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy)ReflectUtils.newInstance(ignoreUrlPatternType, new Object[0]);
} catch (IllegalArgumentException var6) {
this.logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, var6);
}
}
if (this.ignoreUrlPatternMatcherStrategyClass != null) {
this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
}
}
String gatewayStorageClass = this.getPropertyFromInitParams(filterConfig, "gatewayStorageClass", (String)null);
if (gatewayStorageClass != null) {
this.gatewayStorage = (GatewayResolver)ReflectUtils.newInstance(gatewayStorageClass, new Object[0]);
}
String authenticationRedirectStrategyClass = this.getPropertyFromInitParams(filterConfig, "authenticationRedirectStrategyClass", (String)null);
if (authenticationRedirectStrategyClass != null) {
this.authenticationRedirectStrategy = (AuthenticationRedirectStrategy)ReflectUtils.newInstance(authenticationRedirectStrategyClass, new Object[0]);
}
}
}