前言:今天在網上無心間看到cas單點登陸排除請求的問題,發現不少人在討論如何經過改寫AuthenticationFilter類來實現忽略/排除請求URL的功能;突發奇想搜了一下,還真蠻多人都是這麼幹的,原諒我是個耿直的boy,當時我笑的飯都噴出來了,只須要一個配置的問題,被大家搞的這麼麻煩;雖然很想回復他們「大家這幫人用別人的東西都不看源碼的嗎?」,轉念一想,這也要怪做者不給力,文檔裏壓根沒有提到這個配置,在這裏用少許篇幅講解如何配置排除不須要攔截的請求URL,後面用大量篇幅介紹我是如何從源碼中得知這個配置的,但願對你們有用!作好本身!--eguid始終堅持原創的開源技術文章分享,博客園與本博客保持同步更新。歡迎你們加羣一塊兒交流:608423839css
http://blog.csdn.net/eguid_1/article/details/51278622,cas-client完整配置。html
沒有實現忽略/排除請求URL的cas-client登陸驗證過濾器java
<filter> <filter-name>casAuthenticationFilter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>https://cas.eguid.cc/cas-server/</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://client.eguid.cc/</param-value> </init-param> </filter> <filter-mapping> <filter-name>casAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter> <filter-name>casAuthenticationFilter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>http://cas.eguid.cc/cas-server/</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://cilent.eguid.cc/</param-value> </init-param> <init-param> <description>不攔截的請求(作好本身!--eguid)</description> <param-name>ignorePattern</param-name> <param-value>/js/*|/img/*|/view/*|/css/*</param-value> </init-param> </filter> <filter-mapping> <filter-name>casAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
看源碼,必定要帶着目的去看;咱們的目的就是找AuthenticationFilter這個cas-client默認登陸驗證過濾器是否具備排除登陸請求URL的功能。git
打開github上的cas-client項目,能夠把項目導到本地或者直接在github上找到org.jasig.cas.client.authentication.AuthenticationFilter.java這個類。github
既然是個過濾器,就直接找到該類的doFilter方法正則表達式
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { <!--作好本身!eguid原創--> final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; 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; } final String serviceUrl = constructServiceUrl(request, response); final String ticket = retrieveTicketFromRequest(request); final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl); if (CommonUtils.isNotBlank(ticket) || wasGatewayed) { filterChain.doFilter(request, response); return; } final String modifiedServiceUrl; logger.debug("no ticket and no assertion found"); if (this.gateway) { logger.debug("setting gateway attribute in session"); modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl); } else { modifiedServiceUrl = serviceUrl; } logger.debug("Constructed service url: {}", modifiedServiceUrl); final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway); logger.debug("redirecting to \"{}\"", urlToRedirectTo); this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo); }
第一眼就看到了上面代碼紅色標識處的isRequestUrlExcluded,這個意思很直白,判斷是否是須要忽略/排除的請求URL。session
繼續接着找到isRequestUrlExcluded這個方法的實現代碼:app
private boolean isRequestUrlExcluded(final HttpServletRequest request) { if (this.ignoreUrlPatternMatcherStrategyClass == null) { return false; } <!--作好本身!eguid原創--> final StringBuffer urlBuffer = request.getRequestURL(); if (request.getQueryString() != null) { urlBuffer.append("?").append(request.getQueryString()); } final String requestUri = urlBuffer.toString(); return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri); }看紅色標識位置的名字,這裏用到了UrlPatternMatcherStrategy這個類,意思很簡單直白:‘請求url的匹配策略類’,暫時還不知道這裏是正則匹配,日後看:
private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;發現該類是在初始化方法中進行初始化的:
protected void initInternal(final FilterConfig filterConfig) throws ServletException { if (!isIgnoreInitConfiguration()) { super.initInternal(filterConfig); setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL)); setRenew(getBoolean(ConfigurationKeys.RENEW)); setGateway(getBoolean(ConfigurationKeys.GATEWAY)); <!--作好本身!eguid原創--> final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN); final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE); if (ignorePattern != null) { final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType); if (ignoreUrlMatcherClass != null) { this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName()); } else { try { logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType); this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType); } catch (final IllegalArgumentException e) { logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e); } } if (this.ignoreUrlPatternMatcherStrategyClass != null) { this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern); } } final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS); if (gatewayStorageClass != null) { setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass)); } final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS); if (authenticationRedirectStrategyClass != null) { this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass); } } }雖然使用了反射,可是依然不影響咱們找到根本所在,找到ConfigurationKeys這個類裏面的變量到底是什麼:
ConfigurationKey<String> IGNORE_PATTERN = new ConfigurationKey<String>("ignorePattern", null); ConfigurationKey<String> IGNORE_URL_PATTERN_TYPE = new ConfigurationKey<String>("ignoreUrlPatternType", "REGEX");字面上理解這兩個常量定義了忽略模式以及忽略模式類型是‘正則’,固然咱們仍是不肯定是否是正則,那麼繼續往下找
final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
咱們已經經過ConfigurationKeys類知道ignoreUrlPatternType是個‘REGEX’字符串,那麼ui
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);那麼按照REGEX對應的值找到 RegexUrlPatternMatcherStrategy這個類:
public final class RegexUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy { <!--作好本身!eguid原創--> private Pattern pattern; public RegexUrlPatternMatcherStrategy() {} public RegexUrlPatternMatcherStrategy(final String pattern) { this.setPattern(pattern); } public boolean matches(final String url) { return this.pattern.matcher(url).find(); } public void setPattern(final String pattern) { this.pattern = Pattern.compile(pattern); } }該類中用到了Pattern來編譯和匹配正則表達式
到這裏咱們終於能夠肯定能夠用ignorePattern來忽略/排除咱們不須要攔截的請求URL,固然必須知足正則表達式。
this