同事提了一个要求,要求对外提供的接口不需要经过单点登录验证,我刚开始想,这简单,提供不需要拦截的url数组,在AuthenticationFilter里面对url进行检查,在此数组内,就不需要拦截。
下面是AuthenticationFilter类的doFilter方法的部分源码:
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; //在此写验证url if (isRequestUrlExcluded(request)) { logger.debug("Request is ignored."); filterChain.doFilter(request, response); return; } final HttpSession session = request.getSession(false); final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null; if (assertion != null) { filterChain.doFilter(request, response); return; }
以上是部分源码,本来我想在注释的地方,对url进行检查,但是下面一行的 isRequestUrlExcluded(request),这不正是检查URL排除的地方吗?原来cas-client已经实现了此功能。下面我们一步步的梳理代码。
isRequestUrlExcluded的方法如下:
private boolean isRequestUrlExcluded(final HttpServletRequest request) { if (this.ignoreUrlPatternMatcherStrategyClass == null) { return false; } final StringBuffer urlBuffer = request.getRequestURL(); if (request.getQueryString() != null) { urlBuffer.append("?").append(request.getQueryString()); } final String requestUri = urlBuffer.toString(); return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri); }
我们可以看到这里的关键是ignoreUrlPatternMatcherStrategyClass,忽略Url模式验证策略类。
1 protected void initInternal(final FilterConfig filterConfig) throws ServletException { 2 if (!isIgnoreInitConfiguration()) { 3 super.initInternal(filterConfig); 4 setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL)); 5 setRenew(getBoolean(ConfigurationKeys.RENEW)); 6 setGateway(getBoolean(ConfigurationKeys.GATEWAY)); 7 8 final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN); 9 final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);10 11 if (ignorePattern != null) {12 final Class ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);13 if (ignoreUrlMatcherClass != null) {14 this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName());15 } else {16 try {17 logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);18 this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType);19 } catch (final IllegalArgumentException e) {20 logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e);21 }22 }
红色部分是实例化,是关键。我们从第八行开始看起,分别是获取ignorePattern和ignoreUrlPatternType参数,两者的意思分别是忽略的url和忽略的模式。
ConfigurationKeyIGNORE_PATTERN = new ConfigurationKey ("ignorePattern", null); ConfigurationKey IGNORE_URL_PATTERN_TYPE = new ConfigurationKey ("ignoreUrlPatternType", "REGEX");
可以看到代码默认的识别url的方式是正则表达式。而识别方式一共有三种,我们看一下PATTERN_MATCHER_TYPES,分别是包含、正则和精确。
1 private static final Map> PATTERN_MATCHER_TYPES =2 new HashMap >();3 4 static {5 PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);6 PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);7 PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);8 }
因此,我们只需在web.xml中的过滤器上添加参数来配置不需要单点登录拦截url(例子是如果url中包含/service/,则不需要经过单点登录验证)。
casAuthenticationFilter org.jasig.cas.client.authentication.AuthenticationFilter casServerLoginUrl http://cas.eguid.cc/cas-server/ serverName http://cilent.eguid.cc/ 不拦截的请求 ignorePattern /service/ 识别模式 ignoreUrlPatternType CONTAINS casAuthenticationFilter /*