03 spring security执行流程分析
spring security主要是依赖一系列的Filter来实现权限验证的,责任链设计模式是跑不了的。下面简单记录一下spring操作这些Filter的过程。
1. WebSecurityConfiguration.java
该类是spring security的一个配置类,里面定了一系列的Bean,咱主要是看springSecurityFilterChain这个bean, 就是它创建了FilterChain.
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
// 通过webSecurity来构建了FilterChain
return webSecurity.build();
}
2. AbstractConfiguredSecurityBuilder.java
在该类中就加载我们配置权限规则,以及spring security默认的一系列Filter, 权限规则就是01 02篇中我们自定义的SecurityConfig.java类,示例代码如下:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 配置的权限规则
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// todo }
}
再看看AbstractConfiguredSecurityBuilder.java中部分源码,就是在这段代码里面加载了屁多的东西,暂时还没看明白。。。
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING; beforeInit(); init(); buildState = BuildState.CONFIGURING; beforeConfigure();
//
configure(); buildState = BuildState.BUILDING; //
O result = performBuild(); buildState = BuildState.BUILT; return result;
}
}
3. SecurityContextPersistenceFilter.java
This filter will only execute once per request, to resolve servlet container(specifically Weblogic) incompatibilities.
该filter每个请求只执行一次,主要是解决servlet容器的兼容性问题。
This filter MUST be executed BEFORE any authentication processing mechanisms.
必须在权限认证之前执行
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getAttribute(FILTER_APPLIED) != null) {
// ensure that filter is only applied once per request
chain.doFilter(request, response);
return;
}
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
// 设置security的上下文context
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,response);
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
// 开始执行chain上的filter
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
// 清除security的上下文context
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
repo.saveContext(contextAfterChainExecution, holder.getRequest(),holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
}
}

由上面的debug截图可知,FilterSecurityInterceptor.java是链上最后一个Filter,它会对权限进行验证
InterceptorStatusToken token = super.beforeInvocation(fi);
就是在它父类AbstractSecurityInterceptor#beforeInvocation(fi)方法中,进行权限验证,且继续看代码

这儿抛异常会被它前一个Filter捕获,也就是会被ExceptionTranslationFilter.java捕获。

在上面的异常处理中,如果没有权限就会进行重定向到登录页面


下面进入LoginUrlAuthenticationEntryPoint#commence(HttpServletRequest request, HttpServletResponse response,AuthenticationException authException)

4. 登录页面

提交请求之后,又会执行整个filterchain, 此次我们重点分析UsernamePasswordAuthenticationFilter.java, 因为,使用Form表登录,会在该类进行权限验证,下面来看看具体的逻辑
5. UsernamePasswordAuthenticationFilter.java
该类主要就是进行权限验证
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// 非post请求,直接抛异常
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
// 从request对象中获取username , password
String username = obtainUsername(request);
String password = obtainPassword(request); if (username == null) {
username = "";
} if (password == null) {
password = "";
} username = username.trim(); // 创建一个token,该token对象持有用户信息
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // 获取用登录的ip, session相关的信息
setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest);
}
debug看一下return this.getAuthenticationManager().authenticate(authRequest)之前的情况

接着,看看this.getAuthenticationManager().authenticate(authRequest)该方法。
好, 下面进入AuthenticationManager接口的具体实现ProviderManager#authenticate(Authentication authentication)方法

跟踪代码,我们最终会看到这样一个方法DaoAuthenticationProvider#retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)
protected final UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
try {
// this.getUserDetailsService() 这个就是我们实现UserDetailsService接口的MyUserDetailsService.java
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
catch (UsernameNotFoundException ex) {
mitigateAgainstTimingAttack(authentication);
throw ex;
}
catch (InternalAuthenticationServiceException ex) {
throw ex;
}
catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
该方法返回UserDetails 对象后,又会进入到AbstractUserDetailsAuthenticationProvider#authenticate(Authentication authentication)方法,然后对UserDetails 对象做些后置检测,
比如,账号是否锁定,是否过期,是否可用。。。
在最最后面,spring secutiry会再次创建一个UsernamePasswordAuthenticationToken对象的token,不过此次与前面创建的不同,前面创建的token中只有username和password ,
此次会调用UsernamePasswordAuthenticationToken 三个参数的构造器
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}

再继续,代码会走到AbstractAuthenticationProcessingFilter#successfulAuthentication(...)方法,该方法内容,会调用我们自定义的成功的Handler处理器

如果中间抛出异常,会被catch捕获 ,然后走入到自定义的登录失败handler处理器

未完待续。。。
03 spring security执行流程分析的更多相关文章
- Spring Security认证流程分析--练气后期
写在前面 在前一篇文章中,我们介绍了如何配置spring security的自定义认证页面,以及前后端分离场景下如何获取spring security的CSRF Token.在这一篇文章中我们将来分析 ...
- 【权限管理】Spring Security 执行流程
转自:https://blog.csdn.net/weixin_37689658/article/details/92752890 1.基本配置使用 (1)创建配置类 创建一个配置类SecurityC ...
- Spring Security 源码分析(四):Spring Social实现微信社交登录
社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ.人人网.开心网.新浪微博.搜狐微博.腾讯微博.淘宝.豆瓣.MSN.Google等社会化媒体账号登录该网站. 前言 ...
- Spring Security 源码分析 --- WebSecurity
概述 spring security 源码分析系列文章. 源码分析 我们想一下,我们使用 ss 框架的步骤是怎么样的. @Configuration @EnableWebSecurity @Enabl ...
- 一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: ...
- Java——一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...
- 报时机器人的rasa shell执行流程分析
本文以报时机器人为载体,介绍了报时机器人的对话能力范围.配置文件功能和训练和运行命令,重点介绍了rasa shell命令启动后的程序执行过程. 一.报时机器人项目结构 1.对话能力范围 (1)能够 ...
- Spring 文件上传MultipartFile 执行流程分析
在了解Spring 文件上传执行流程之前,我们必须知道两点: 1.Spring 文件上传是基于common-fileUpload 组件的,所以,文件上传必须引入此包 2.Spring 文件上传需要在X ...
- spring security源码分析之web包分析
Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案.一般来说,Web 应用的安全性包括 ...
随机推荐
- Dpr ppi 适配 等概念 弹性属性的讲解
Dpr: Dpr的全称(Device pixel ratio)像素设备比例:就是说每个设备像素上占有的css位像素的个数 苹果手机常见的设备像素比:1.0安卓 iPhone2.0 3.0 如果是1. ...
- Selenium WebDriver 常用API
public class Demo1 { WebDriver driver; @BeforeMethod public void visit(){ //webdriver对象的声明 System.se ...
- php远程抓取(下载)文件到本项目指定目录中
function httpcopy($url, $file="", $timeout=60) { $file = empty($file) ? pathinfo($url,PATH ...
- 【OpenGL】---认识CubeTexture
一.OpenGL Cube Texture 立方体纹理 立方体纹理是一种特殊的纹理技术,他用6幅二维贴图构成一个以原点为中心的纹理立方体.对于每个片段,纹理坐标(s,t,r)被当做三维向量看待,每个纹 ...
- MySQL-第五篇视图
1.视图看上去像是表,但它又不是,它并不能存储数据.视图只是一个或者多个表的逻辑显示.使用视图的好处: 1>可以限制对数据的访问 2>可以使复杂的查询变得简单 3>提供了数据的独立性 ...
- Server Tomcat v8.5 Server at localhost failed to start.
问题描述:新建了一个项目,建立servlet文件然后改了下@WebServlet("floorButtonServlet")映射的路径,重启debug之后服务器启动失败. 在网上查 ...
- 状压BFS
题意:1个机器人找几个垃圾,求出最短路径. 状压BFS,这道题不能用普通BFS二维vis标记数组去标记走过的路径,因为这题是可以往回走的,而且你也不能只记录垃圾的数量就可以了,因为它有可能重复走同一 ...
- Vue2.0源码阅读笔记(四):nextTick
在阅读 nextTick 的源码之前,要先弄明白 JS 执行环境运行机制,介绍 JS 执行环境的事件循环机制的文章很多,大部分都阐述的比较笼统,甚至有些文章说的是错误的,以下为个人理解,如有错误, ...
- cronsun任务管理器部署文档
一.cronsun介绍 1)cronsun产生的背景 大量的 crontab 任务散布在各台服务器,带来了很高的维护成本 任务没有按时执行,甚至失败了很久才发现,需要重试或排查 crontab 分散在 ...
- shell脚本从入门到精通(初级)之入门篇
写在开头 本文是阅读<Linux命令行与shell脚本编程大全>时的一些笔记,主要是shell脚本的一些基本语法, 还有很多细节和高级内容没有写到. 笔者也是shell script菜鸟, ...