最近维护一个老的SpringMVC的应用,增加CAS单点登录。但是有个特殊的需求是保留系统本身的认证,根据需要可以走CAS单点登录认证,也可以走系统本身的认证。
设计的方案是根据输入的URL进行判断,是否跳过CAS的Filter还是跳过系统本来的认证Filter。
下面上代码:
POM文件:
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.5.0</version>
</dependency>
web.xml
<filter>
<filter-name>FirstFilter</filter-name>
<display-name>FirstFilter</display-name>
<description></description>
<filter-class>com.test.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>http://localhost:8080/cas-server</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>http://localhost:8080/cas-server/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>CAS Filter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>http://localhost:8080/cas-server</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
关键的FirstFilter的代码:
说明:chain 有个filters的属性数组,是过滤器链,里边放的是ApplicationFilterConfig 是FilterConfig的一个实现类,ApplicationFilterConfig里有个属性叫filterDef就是过滤器定义,这个类的FilterClass和FilterName保存了过滤器类和过滤器名,这样就可以根据过滤器类或名字找到要剔除的过滤器,然后将对应的ApplicationFilterConfig 从数组里剔除就可以了。剔除不能是置为null就完了,因为它是从头往后依次执行的,如果中间有null会报错,要置null后将后边的往前移,还有就是要改chain过滤器个数属性。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String url = ((HttpServletRequest)request).getRequestURL().toString();
String queryString = ((HttpServletRequest)request).getQueryString();
String[] filterStrings = {"AuthenticationFilter", "Cas10TicketValidationFilter", "HttpServletRequestWrapperFilter", "AssertionThreadLocalFilter", "SingleSignOutFilter"};
if(queryString != null) {
if(queryString.endsWith("111")) {
try {
Field field = chain.getClass().getDeclaredField("filters");
field.setAccessible(true);
FilterConfig[] filters = (FilterConfig[])field.get(chain);
int k = 0;
for (int i = 0;i< filters.length;i++) {
if (filters[i]!=null) {
Field field2 = filters[i].getClass().getDeclaredField("filterDef");
field2.setAccessible(true);
Field field3 = field2.get(filters[i]).getClass().getDeclaredField("filterClass");
field3.setAccessible(true);
String filterClass = (String)field3.get(field2.get(filters[i]));
for (String str1 : filterStrings) {
if(filterClass.endsWith(str1)) {
filters[i] = null;
k++;
break;
}
}
field3.setAccessible(false);
field2.setAccessible(false);
}
}
int index = 0;
for(int i = 0; i< filters.length; i++) {
if (index==0 && filters[i] == null) {
index = i;
}
else if(index != 0 && filters[i] != null) {
filters[index] = filters[i];
filters[i] = null;
i = index;
index = 0;
}
}
field.setAccessible(false);
Field n = chain.getClass().getDeclaredField("n");
n.setAccessible(true);
n.set(chain,n.getInt(chain)-k);
n.setAccessible(false);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
chain.doFilter(request, response);
}