前言:网络中关于Spring security整合cas的方案有很多例,对于Springboot security整合cas方案则比较少,且有些仿制下来运行也有些错误,所以博主在此篇详细的分析cas原理以及Springboot如何正确的配置cas环境

CAS原理

首先整合cas方案的话,无疑理解cas的原理是迫在眉睫的,这在后面对理解代码也有很好的帮助,此处可查看别人写的文章>>>CAS实现SSO单点登录原理,博主只在这里针对springboot cas整合罗列出了其中的逻辑

以上的逻辑看起来比较抽象,下面我们结合源码部分对其作补充

CAS代码逻辑

我们需要熟悉下以下这几个Filter类

- SingleSignOutFilter 单点注销Filter类,接收cas服务端发出的注销session请求
- LogoutFilter 登录退出Filter类,转发至cas服务端进行注销
- CasAuthenticationFilter cas校验Filter处理类,包括对含有token的请求或者指定的路径请求处理
- ExceptionTranslationFilter 异常Filter处理类,主要是接受AccessDeniedException/AuthenticationException这两个异常,其中涉及转发请求至cas服务端登录页面
- FilterSecurityInterceptor 权限验证处理类

SingleSignOutFilter

主要涉及session的创建以及销毁,响应token请求、SLO的前后通道请求,源码如下

	//最终处理请求响应类
private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler();
//是否已初始化,默认为false
private AtomicBoolean handlerInitialized = new AtomicBoolean(false); //复写Filter类的init方法,主要是初始化参数
public void init(final FilterConfig filterConfig) throws ServletException {
//初始化ConfigurationStrategy策略类,默认为LegacyConfigurationStrategyImpl实现类
super.init(filterConfig);
//ignoreInitConfiguration是否为true,false则采用ConfigurationStrategy的相应参数名
if (!isIgnoreInitConfiguration()) {
//设置凭证参数,默认为ticket
setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME));
//设置登录退出参数,默认为logoutRequest
setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME));
//设置前台通道参数,默认为SAMLRequest,基于SAML实现,此处可自行查阅
setFrontLogoutParameterName(getString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME));
//设置RelayState参数,默认为RelayState
setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME));
//设置cas服务端前缀,比如https://example.cas.com/cas
setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX)); HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST));
HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS));
}
//主要设置safeParameters参数,默认只有logoutParameterName,即logoutRequest
HANDLER.init();
//设置为已初始化
handlerInitialized.set(true);
}

进而继续查看SingleSignOutFilter#doFilter方法,看其中的处理逻辑

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse; //判断有无初始化
if (!this.handlerInitialized.getAndSet(true)) {
HANDLER.init();
}
//通过SingleSignOutHandler类处理请求,只有返回true才放行
if (HANDLER.process(request, response)) {
filterChain.doFilter(servletRequest, servletResponse);
}
}

核心处理类SingleSignOutHandler#process()的代码如下

public boolean process(final HttpServletRequest request, final HttpServletResponse response) {
//判断是否是token请求,即request对象中是否含有ticket属性
if (isTokenRequest(request)) {
logger.trace("Received a token request");
//保存当前的会话
recordSession(request); return true; }
//POST请求&非文件上传请求&request对象含有logoutRequest属性
else if (isBackChannelLogoutRequest(request)) {
logger.trace("Received a back channel logout request");
//销毁会话
destroySession(request);
return false; }
//GET请求&casServerUrlPrefix已设置&request对象含有SAMLRequest属性
else if (isFrontChannelLogoutRequest(request)) {
logger.trace("Received a front channel logout request");
destroySession(request);
// redirection url to the CAS server 拼装至cas服务端的logout请求
final String redirectionUrl = computeRedirectionToServer(request);
if (redirectionUrl != null) {
CommonUtils.sendRedirect(response, redirectionUrl);
}
return false; } else {
//对非logout请求都进行放行
return true;
}
}
  1. SingleSignOutFilter主要响应的是对cas服务端注销后对客户端应用的注销请求,其需要LogoutFilter的配合。这里涉及到SLO/SAML的概念,有兴趣的可自行查阅
  2. 放行策略:对已含有tokenticket参数的请求放行;非SLO logout请求放行

LogoutFilter

登录退出过滤类,是比较简单的Filter类,实现上也比较简单,简单看下

  • 构造函数
	public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler,
LogoutHandler... handlers) {
//两个参数都不能为空
Assert.notEmpty(handlers, "LogoutHandlers are required");
this.handlers = Arrays.asList(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
this.logoutSuccessHandler = logoutSuccessHandler;
//默认接受的登录退出请求为 /logout
setFilterProcessesUrl("/logout");
} //设置退出操作成功后跳转的url:logoutSuccessUrl,此处一般为跳转至cas服务端退出路径并携带service回调路径
public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
Assert.notEmpty(handlers, "LogoutHandlers are required");
this.handlers = Arrays.asList(handlers);
Assert.isTrue(
!StringUtils.hasLength(logoutSuccessUrl)
|| UrlUtils.isValidRedirectUrl(logoutSuccessUrl),
logoutSuccessUrl + " isn't a valid redirect URL");
SimpleUrlLogoutSuccessHandler urlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
if (StringUtils.hasText(logoutSuccessUrl)) {
urlLogoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
}
logoutSuccessHandler = urlLogoutSuccessHandler;
setFilterProcessesUrl("/logout");
}
  • doFilter()逻辑
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//即匹配当前的请求是否为指定的响应请求,默认判断是否为/logout
if (requiresLogout(request, response)) {
//获取上下文中的Authentication 凭证信息
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth
+ "' and transferring to logout destination");
}
//一般是销毁session和清除Authentication 凭证信息,比如SecurityContextLogoutHandler
for (LogoutHandler handler : handlers) {
handler.logout(request, response, auth);
}
//跳转至cas服务端注销页面
logoutSuccessHandler.onLogoutSuccess(request, response, auth); return;
}
//非logout请求放行
chain.doFilter(request, response);
}

LogoutFilter的逻辑比较简单,主要是对logout请求进行响应,具体作用是

  1. 销毁session以及安全上下文的Authentication 凭证对象

  2. 跳转至cas服务端注销页面,这里可以配置跳转路径为 casServerUrlPrefix+casServerLogoutUrl+"?service="+casAppServiceUrl

  3. cas服务端回调service来销毁客户端缓存的session,即SingleSignOutFilter

CasAuthenticationFilter

CasAuthenticationFilter涉及的篇幅较长,可点击>>>Springboot security cas源码陶冶-CasAuthenticationFilter

ExceptionTranslationFilter

异常处理类,主要涉及对AuthenticationExceptionAcessDeniedException的响应,在cas中主要应用为出现授权/校验错误则转发路径到casServerLoginUrl供用户统一登录,具体的可查看>>>Springboot security cas源码陶冶-ExceptionTranslationFilter

FilterSecurityInterceptor

授权拦截器,可点击>>>Springboot security cas源码陶冶-FilterSecurityInterceptor

spring security cas逻辑示意图

通过此图再结合以上的代码分析,便可以深入理解spring security是如何整合cas了

下节预告

Springboot security cas整合方案-实践篇

Springboot security cas整合方案-原理篇的更多相关文章

  1. Springboot security cas整合方案-实践篇

    承接前文Springboot security cas整合方案-原理篇,请在理解原理的情况下再查看实践篇 maven环境 <dependency> <groupId>org.s ...

  2. Springboot security cas源码陶冶-CasAuthenticationFilter

    Springboot security cas整合方案中不可或缺的校验Filter类或者称为认证Filter类,其内部包含校验器.权限获取等,特开辟新地啃啃 继承结构 - AbstractAuthen ...

  3. Springboot security cas源码陶冶-ExceptionTranslationFilter

    拦截关键的两个异常,对异常进行处理.主要应用异常则跳转至cas服务端登录页面 ExceptionTranslationFilter#doFilter-逻辑入口 具体操作逻辑如下 public void ...

  4. Springboot security cas源码陶冶-FilterSecurityInterceptor

    前言:用户登录信息校验成功后,都会获得当前用户所拥有的全部权限,所以对访问的路径当前用户有无权限则需要拦截验证一发 Spring security过滤器的执行顺序 首先我们需要验证为啥FilterSe ...

  5. 玩转 SpringBoot 2 之整合 JWT 下篇

    前言 在<玩转 SpringBoot 2 之整合 JWT 上篇> 中介绍了关于 JWT 相关概念和JWT 基本使用的操作方式.本文为 SpringBoot 整合 JWT 的下篇,通过解决 ...

  6. SpringBoot 2.X整合Mybatis

    1.创建工程环境 勾选Web.Mybatis.MySQL,如下 依赖如下 <dependency> <groupId>org.springframework.boot</ ...

  7. 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录

    [手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...

  8. springboot+security整合(3)自定义鉴权

    说明 springboot 版本 2.0.3源码地址:点击跳转 系列 springboot+security 整合(1) springboot+security 整合(2) springboot+se ...

  9. springboot+security整合(2)自定义校验

    说明 springboot 版本 2.0.3源码地址:点击跳转 系列 springboot+security 整合(1) springboot+security 整合(2) springboot+se ...

随机推荐

  1. 浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍

    浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍 前记 自己是搞编程的,首先我是一个菜鸟,接触计算机这么久了,感觉很多计算机方面的技术和知识朦朦胧胧.模模糊糊,貌似有些贻笑大方了:所 ...

  2. POJ2689-Prime Distance-区间筛素数

    最近改自己的错误代码改到要上天,心累. 这是迄今为止写的最心累的博客. Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total S ...

  3. ICMP TYPE-CODE查阅表

    我们在使用ICMP协议进行作业时,经常会用到ICMP类型和code,这里给出ICMP类型和code对应表. ICMP TYPE CODE对照表 TYPE CODE Description Query ...

  4. [高并发]抢红包设计(使用redis)

    假设一个需求,在某个预告活动中准备了10w个红包,100w人在某个时间点去开抢,每人只能抢1次,如何保证性能和准确性,下面我给出我的一个设计方案,抛砖引玉 分析瓶颈 查询用户是否已参与过活动 获取一个 ...

  5. [数据预处理]-中心化 缩放 KNN(一)

    据预处理是总称,涵盖了数据分析师使用它将数据转处理成想要的数据的一系列操作.例如,对某个网站进行分析的时候,可能会去掉 html 标签,空格,缩进以及提取相关关键字.分析空间数据的时候,一般会把带单位 ...

  6. Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE

    初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...

  7. How to find missing USB Records?

    In my previously article "EnCase missed some USB activities in the evidence files", I ment ...

  8. asp.net -mvc框架复习(11)-基于三层架构与MVC实现完整的用户登录

    一.先从M部分写起(Modles\DAL\BLL) 1.Modles 实体类:上次实体类已经搞定. 2.DAL 数据访问类类 (1)通用数据数据访问类: A:  先编写数据连接字符串,写到网站根目录W ...

  9. Block 的使用时机

    Block 一般是用来表示.简化一小段的程式码,它特别适合用来建立一些同步执行的程式片段.封装一些小型的工作或是用来做为某一个工作完成时的回传呼叫(callback) . 在新的iOS API中blo ...

  10. bug 对应

    异常1:not-null property references a null or transient value解决方法:将“一对多”关系中的“一”方,not-null设置为false http: ...