前言:今天在网上无意间看到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. if (</span><span style="color:#ff0000;">isRequestUrlExcluded</span><span style="color:#24292e;">(request)) {
  7. logger.debug("Request is ignored.");
  8. filterChain.doFilter(request, response);
  9. return;
  10. }
  11. final HttpSession session = request.getSession(false);
  12. final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
  13. if (assertion != null) {
  14. filterChain.doFilter(request, response);
  15. return;
  16. }
  17. final String serviceUrl = constructServiceUrl(request, response);
  18. final String ticket = retrieveTicketFromRequest(request);
  19. final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
  20. if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
  21. filterChain.doFilter(request, response);
  22. return;
  23. }
  24. final String modifiedServiceUrl;
  25. logger.debug("no ticket and no assertion found");
  26. if (this.gateway) {
  27. logger.debug("setting gateway attribute in session");
  28. modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
  29. } else {
  30. modifiedServiceUrl = serviceUrl;
  31. }
  32. logger.debug("Constructed service url: {}", modifiedServiceUrl);
  33. final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
  34. getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
  35. logger.debug("redirecting to \"{}\"", urlToRedirectTo);
  36. this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
  37. }</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. if (ignorePattern != null) {
  11. final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
  12. if (ignoreUrlMatcherClass != null) {
  13. this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName());
  14. } else {
  15. try {
  16. logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
  17. this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType);
  18. } catch (final IllegalArgumentException e) {
  19. logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e);
  20. }
  21. }
  22. if (this.ignoreUrlPatternMatcherStrategyClass != null) {
  23. this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
  24. }
  25. }
  26. final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
  27. if (gatewayStorageClass != null) {
  28. setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));
  29. }
  30. final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
  31. if (authenticationRedirectStrategyClass != null) {
  32. this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
  33. }
  34. }
  35. }</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. public RegexUrlPatternMatcherStrategy() {}
  5. public RegexUrlPatternMatcherStrategy(final String pattern) {
  6. this.setPattern(pattern);
  7. }
  8. public boolean matches(final String url) {
  9. return this.pattern.matcher(url).find();
  10. }
  11. public void setPattern(final String pattern) {
  12. this.pattern = Pattern.compile(pattern);
  13. }
  14. }

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

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

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

  1. cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题

    http://blog.csdn.net/eguid_1/article/details/73611781

  2. [精华][推荐]CAS SSO 单点登录框架学习 环境搭建

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  3. CAS SSO单点登录框架学习

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  4. CAS SSO单点登录框架介绍

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  5. 基于CAS的单点登录实战(2)-- 搭建cas的php客户端

    在这之前已经搭好了CAS服务端 基于CAS的单点登录实战(1)-- 搭建cas服务器 PHP-Client php-Client是官方支持的,去官网下个最新版就好了.phpCAS 接入很简单,解压放到 ...

  6. [精华][推荐]CAS SSO单点登录服务端客户端实例

    1.修改server.xml文件,如下: 注意: 这里使用的是https的认证方式,需要将这个配置放开,并做如下修改: <Connector port="8443" prot ...

  7. Cas(07)——建立使用Cas进行单点登录的应用

    建立使用Cas进行单点登录的应用 目录 1.1加入cas-client-core-xxx.jar到classpath 1.2配置Filter 1.2.1AuthenticationFilter 1.2 ...

  8. CAS实现单点登录SSO执行原理及部署

    一.不落俗套的开始 1.背景介绍 单点登录:Single Sign On,简称SSO,SSO使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. CAS框架:CAS(Centra ...

  9. CAS实现单点登录

    1.简介 SSO单点登录 在多个相互信任的系统中,用户只需要登录一次就可以访问其他受信任的系统. 新浪微博与新浪博客是相互信任的应用系统. *当用户首次访问新浪微博时,新浪微博识别到用户未登录,将请求 ...

随机推荐

  1. ES6之"let"能替代"var"吗?

    译者按: 使用let的确会比var安全很多. 原文: Why You Shouldn't Use 'var' Anymore 译者: Fundebug 为了保证可读性,本文采用意译而非直译. 我已经使 ...

  2. redis性能优化

    redis日志截图:

  3. java中多种写文件方式的效率对比实验

    一.实验背景 最近在考虑一个问题:“如果快速地向文件中写入数据”,java提供了多种文件写入的方式,效率上各有异同,基本上可以分为如下三大类:字节流输出.字符流输出.内存文件映射输出.前两种又可以分为 ...

  4. ES6入门2

    for-of循环: 新语法如下: for (var value of myArray) { console.log(value); } 它的优点是: 这是目前遍历数组最简洁和直接的语法: 它避免了fo ...

  5. 初识mysql

    一直想试试mysql,但是却一直没有正式的使用过它,也许是因为第一次安装时忘记了root密码,折腾太久留下的后遗症吧,总有点怕怕的.今天第一次使用命令行创建了数据库和数据表,虽然是简单的不能再简单的数 ...

  6. .net 非对称加密

    后台   public class RSAHelper     {         /// <summary>         /// RSA加密         /// </sum ...

  7. Libsvm使用资料

    原理: 1. pluskid(张弛原)的支持向量机教程(人家现在都是大牛了) http://blog.pluskid.org/?page_id=683 2. JerryLead机器学习教程 http: ...

  8. Redis 小白指南(二)- 基础命令和五大类型:字符串、散列、列表、集合和有序集合

    Redis 小白指南(二)- 基础命令和五大类型:字符串.散列.列表.集合和有序集合 引言 目录 基础命令 字符串类型 散列类型 列表类型 集合类型 有序集合类型 基础命令 1.获得符合规则的键名列表 ...

  9. ECMAScript 6.0 简介

    ECMAScript 6.0 在es6中有 许多语法.还有lambda的使用.以及 class 的使用 还有一些新的对象来解决一些事情 可以提高开发效率 但更重要的是 颠覆 javascript 在你 ...

  10. javascript中break和continue的区别

    1.break:跳出循环. 2.continue:跳过循环中的一个迭代.(迭代:重复反馈过程的滑动,其目的是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代",而每一次迭代 ...