cas-client單點登陸客戶端攔截請求和忽略/排除不須要攔截的請求URL的問題

前言:今天在網上無心間看到cas單點登陸排除請求的問題,發現不少人在討論如何經過改寫AuthenticationFilter類來實現忽略/排除請求URL的功能;突發奇想搜了一下,還真蠻多人都是這麼幹的,原諒我是個耿直的boy,當時我笑的飯都噴出來了,只須要一個配置的問題,被大家搞的這麼麻煩;雖然很想回復他們「大家這幫人用別人的東西都不看源碼的嗎?」,轉念一想,這也要怪做者不給力,文檔裏壓根沒有提到這個配置,在這裏用少許篇幅講解如何配置排除不須要攔截的請求URL,後面用大量篇幅介紹我是如何從源碼中得知這個配置的,但願對你們有用!作好本身!--eguid始終堅持原創的開源技術文章分享,博客園與本博客保持同步更新。歡迎你們加羣一塊兒交流:608423839css

一、cas-client單點登陸配置

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>

這個配置依然是可用的,固然咱們要實現忽略/排除請求URL的功能,那麼咱們該怎麼作呢?

二、忽略/排除多個請求URL

<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>



如上所見,咱們排除了四個請求URL(必須是正則表達式形式,下面會講爲何要這麼配置)

三、cas-client默認登陸驗證過濾器源碼解析

看源碼,必定要帶着目的去看;咱們的目的就是找AuthenticationFilter這個cas-client默認登陸驗證過濾器是否具備排除登陸請求URL的功能。git

(1)打開cas-client項目源碼

打開github上的cas-client項目,能夠把項目導到本地或者直接在github上找到org.jasig.cas.client.authentication.AuthenticationFilter.java這個類。github

(2)登陸驗證過濾器AuthenticationFilter的doFilter

既然是個過濾器,就直接找到該類的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); }

(3)isRequestUrlExcluded方法

第一眼就看到了上面代碼紅色標識處的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的匹配策略類’,暫時還不知道這裏是正則匹配,日後看:

(4)請求URL的匹配策略類UrlPatternMatcherStrategy

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這個類:

(5)肯定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

相關文章
相關標籤/搜索