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

来源:互联网 发布:程序员 工资 编辑:程序博客网 时间:2024/05/24 01:18

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

1、cas-client单点登录配置

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

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

<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的功能,那么我们该怎么做呢?

2、忽略/排除多个请求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(必须是正则表达式形式,下面会讲为什么要这么配置)

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

   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。

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

 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’字符串,那么

   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,当然必须满足正则表达式。


阅读全文
2 0
原创粉丝点击