• 关于cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题(不需要修改任何代码,只需要一个配置)


    前言:今天在网上无意间看到cas单点登录排除请求的问题,发现很多人在讨论如何通过改写AuthenticationFilter类来实现忽略/排除请求URL的功能;突发奇想搜了一下,还真蛮多人都是这么干的,原谅我是个耿直的boy,当时我笑的饭都喷出来了,只需要一个配置的问题,被你们搞的这么麻烦;虽然很想回复他们“你们这帮人用别人的东西都不看源码的吗?”,转念一想,这也要怪作者不给力,文档里压根没有提到这个配置,在这里用少量篇幅讲解如何配置排除不需要拦截的请求URL,后面用大量篇幅介绍我是如何从源码中得知这个配置的,希望对大家有用!做好自己!--eguid始终坚持原创的开源技术文章分享,博客园与本博客保持同步更新。欢迎大家加群一起交流:608423839

    1、cas-client单点登录配置

    http://blog.csdn.net/eguid_1/article/details/51278622,cas-client完整配置。

    没有实现忽略/排除请求URL的cas-client登录验证过滤器

    1. <filter>    
    2.       <filter-name>casAuthenticationFilter</filter-name>    
    3.    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>    
    4.       <init-param>    
    5.          <param-name>casServerLoginUrl</param-name>    
    6.          <param-value>https://cas.eguid.cc/cas-server/</param-value>    
    7.       </init-param>    
    8.       <init-param>    
    9.          <param-name>serverName</param-name>    
    10.          <param-value>http://client.eguid.cc/</param-value>    
    11.       </init-param>    
    12.    </filter>    
    13.    <filter-mapping>    
    14.       <filter-name>casAuthenticationFilter</filter-name>    
    15.       <url-pattern>/*</url-pattern>    
    16.    </filter-mapping>    


    这个配置依然是可用的,当然我们要实现忽略/排除请求URL的功能,那么我们该怎么做呢?

    2、忽略/排除多个请求URL

    1. <filter>  
    2.      <filter-name>casAuthenticationFilter</filter-name>  
    3.   <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>  
    4.      <init-param>  
    5.         <param-name>casServerLoginUrl</param-name>  
    6.         <param-value>http://cas.eguid.cc/cas-server/</param-value>  
    7.      </init-param>  
    8.      <init-param>  
    9.         <param-name>serverName</param-name>  
    10.         <param-value>http://cilent.eguid.cc/</param-value>  
    11.         <param-name>ignorePattern</param-name>  
    12.         <param-value>/js/*|/img/*|/view/*|/css/*</param-value>  
    13.      </init-param>  
    14.   </filter><!--做好自己!eguid原创-->  
    15.   <filter-mapping>  
    16.      <filter-name>casAuthenticationFilter</filter-name>  
    17.      <url-pattern>/*</url-pattern>  
    18.   </filter-mapping>  


    如上所见,我们排除了四个请求URL(必须是正则表达式形式,下面会讲为什么要这么配置)

    3、cas-client默认登录验证过滤器源码解析

    看源码,一定要带着目的去看;我们的目的就是找AuthenticationFilter这个cas-client默认登录验证过滤器是否具有排除登录请求URL的功能。

    (1)打开cas-client项目源码

    打开github上的cas-client项目,可以把项目导到本地或者直接在github上找到org.jasig.cas.client.authentication.AuthenticationFilter.Java这个类。

    (2)登录验证过滤器AuthenticationFilter的doFilter

    既然是个过滤器,就直接找到该类的doFilter方法

    1. <span style="color:#24292e;">   public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,  
    2.             final FilterChain filterChain) throws IOException, ServletException {  
    3.         <!--做好自己!eguid原创-->  
    4.         final HttpServletRequest request = (HttpServletRequest) servletRequest;  
    5.         final HttpServletResponse response = (HttpServletResponse) servletResponse;  
    6.           
    7.         if (</span><span style="color:#ff0000;">isRequestUrlExcluded</span><span style="color:#24292e;">(request)) {  
    8.             logger.debug("Request is ignored.");  
    9.             filterChain.doFilter(request, response);  
    10.             return;  
    11.         }  
    12.           
    13.         final HttpSession session = request.getSession(false);  
    14.         final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;  
    15.   
    16.         if (assertion != null) {  
    17.             filterChain.doFilter(request, response);  
    18.             return;  
    19.         }  
    20.   
    21.         final String serviceUrl = constructServiceUrl(request, response);  
    22.         final String ticket = retrieveTicketFromRequest(request);  
    23.         final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);  
    24.   
    25.         if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {  
    26.             filterChain.doFilter(request, response);  
    27.             return;  
    28.         }  
    29.   
    30.         final String modifiedServiceUrl;  
    31.   
    32.         logger.debug("no ticket and no assertion found");  
    33.         if (this.gateway) {  
    34.             logger.debug("setting gateway attribute in session");  
    35.             modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);  
    36.         } else {  
    37.             modifiedServiceUrl = serviceUrl;  
    38.         }  
    39.   
    40.         logger.debug("Constructed service url: {}", modifiedServiceUrl);  
    41.   
    42.         final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,  
    43.                 getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);  
    44.   
    45.         logger.debug("redirecting to "{}"", urlToRedirectTo);  
    46.         this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);  
    47.     }</span>  

    (3)isRequestUrlExcluded方法

    第一眼就看到了上面代码红色标识处的isRequestUrlExcluded,这个意思很直白,判断是不是需要忽略/排除的请求URL。

    继续接着找到isRequestUrlExcluded这个方法的实现代码:

    1. <span style="color:#24292e;"> private boolean isRequestUrlExcluded(final HttpServletRequest request) {  
    2.         if (this.ignoreUrlPatternMatcherStrategyClass == null) {  
    3.             return false;  
    4.         }  
    5.         <!--做好自己!eguid原创-->  
    6.         final StringBuffer urlBuffer = request.getRequestURL();  
    7.         if (request.getQueryString() != null) {  
    8.             urlBuffer.append("?").append(request.getQueryString());  
    9.         }  
    10.         final String requestUri = urlBuffer.toString();  
    11.         return this.</span><span style="color:#ff0000;">ignoreUrlPatternMatcherStrategyClass</span><span style="color:#24292e;">.matches(requestUri);  
    12.     }</span>  

    看红色标识位置的名字,这里用到了UrlPatternMatcherStrategy这个类,意思很简单直白:‘请求url的匹配策略类’,暂时还不知道这里是正则匹配,往后看:

    (4)请求URL的匹配策略类UrlPatternMatcherStrategy

    1. private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;  

    发现该类是在初始化方法中进行初始化的:

    1. <span style="color:#24292e;"> 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.              <!--做好自己!eguid原创-->            
    8.             final String ignorePattern = getString(ConfigurationKeys.</span><span style="color:#ff0000;">IGNORE_PATTERN</span><span style="color:#24292e;">);  
    9.             final String ignoreUrlPatternType = getString(ConfigurationKeys.</span><span style="color:#ff0000;">IGNORE_URL_PATTERN_TYPE</span><span style="color:#24292e;">);  
    10.               
    11.             if (ignorePattern != null) {  
    12.                 final Class<? extends UrlPatternMatcherStrategy> 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.                 }  
    23.                 if (this.ignoreUrlPatternMatcherStrategyClass != null) {  
    24.                     this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);  
    25.                 }  
    26.             }  
    27.               
    28.             final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);  
    29.   
    30.             if (gatewayStorageClass != null) {  
    31.                 setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));  
    32.             }  
    33.               
    34.             final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);  
    35.   
    36.             if (authenticationRedirectStrategyClass != null) {  
    37.                 this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);  
    38.             }  
    39.         }  
    40.     }</span>  

    虽然使用了反射,但是依然不影响我们找到根本所在,找到ConfigurationKeys这个类里面的变量究竟是什么:

    1. <span style="color:#24292e;">   ConfigurationKey<String> IGNORE_PATTERN = new ConfigurationKey<String>("</span><span style="color:#ff0000;">ignorePattern</span><span style="color:#24292e;">", null);  
    2.     ConfigurationKey<String> IGNORE_URL_PATTERN_TYPE = new ConfigurationKey<String>("</span><span style="color:#ff0000;">ignoreUrlPatternType</span><span style="color:#24292e;">", "REGEX");</span>  

    字面上理解这两个常量定义了忽略模式以及忽略模式类型是‘正则’,当然我们还是不确定是不是正则,那么继续往下找

    1. final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);  

    我们已经通过ConfigurationKeys类知道ignoreUrlPatternType是个‘REGEX’字符串,那么

    1. PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);  

    那么按照REGEX对应的值找到RegexUrlPatternMatcherStrategy这个类:

    (5)确定RegexUrlPatternMatcherStrategy类用于处理正则验证匹配

    1. public final class RegexUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {  
    2. <!--做好自己!eguid原创-->  
    3.     private Pattern pattern;  
    4.   
    5.     public RegexUrlPatternMatcherStrategy() {}  
    6.   
    7.     public RegexUrlPatternMatcherStrategy(final String pattern) {  
    8.         this.setPattern(pattern);  
    9.     }  
    10.       
    11.     public boolean matches(final String url) {  
    12.         return this.pattern.matcher(url).find();  
    13.     }  
    14.   
    15.     public void setPattern(final String pattern) {  
    16.         this.pattern = Pattern.compile(pattern);  
    17.     }  
    18. }  

    该类中用到了Pattern来编译和匹配正则表达式

    到这里我们终于可以确定可以用ignorePattern来忽略/排除我们不需要拦截的请求URL,当然必须满足正则表达式。

    做好自己!--eguid,本文为博主原创文章,转载请注明出处! - -欢迎大家积极开心的加入流媒体讨论群:371249677

    http://www.cnblogs.com/eguid/p/7067882.html

  • 相关阅读:
    【转】STL中map用法详解
    【转】容器 C++ set和map
    .NET简谈面向接口编程 狼人:
    详解.NET程序集的加载规则 狼人:
    ASP.NET MVC 入门介绍 (上) 狼人:
    页面片段缓存(二) 狼人:
    改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects) 狼人:
    改善代码设计 —— 组织好你的数据(Composing Data) 狼人:
    C# 中奇妙的函数联接序列的五种简单方法 狼人:
    Log4Net 全方位跟踪程序运行 狼人:
  • 原文地址:https://www.cnblogs.com/softidea/p/7068189.html
Copyright © 2020-2023  润新知