SpringSecurity客户端认证鉴权流程
创始人
2025-05-29 04:18:40

概述

FilterChainProxy是spring-security的入口,包含默认的和用户自定义过滤器。

当访问任意接口,例如: http://localhost:8035/,请求将进入FilterChainProxy打个断点可以看到只使用用户名密码登录时默认有11个过滤器:

几个重要的过滤器:

  1. SecurityContextPersistenceFilter: 安全上下文持久化过滤器;认证完成后将SpringContext持久化到会话中,使得用户后续请求可以直接获取SpringContext,避免需要重复认证。

其成员变量repo就是持久化仓库,默认实现是HttpSessionSecurityContextRepository,即将SpringContext保存到Session中。

  1. UsernamePasswordAuthenticationFilter: 用户名密码校验过滤器,如果是用户名密码登录请求则开始认证。
  2. AnonymousAuthenticationFilter: 匿名用户认证过滤器,如果当前仍未认证,则构建一个匿名用户保存到SpringContext中。为啥不直接抛出AccessDeniedException呢?因为匿名用户也有可以访问的接口。
  3. ExceptionTranslationFilter: 异常翻译过滤器,主要处理AuthenticationException和AccessDeniedException
  4. FilterSecurityInterceptor: 权限校验过滤器,负责确定当前认证结果是否有访问目标接口的权限,如果没有权限则抛出AccessDeniedException

demo配置

http.authorizeRequests()

.mvcMatchers("/login").permitAll() //匿名用户可访问/login

.anyRequest().authenticated()//代表其他请求需要认证

.and()

.formLogin()//表示开启表单认证

.loginPage("/login")

.loginProcessingUrl("/doLogin");

loginPage:指定自定义登录页面,当拒绝访问时会重定向该页面,注意:一旦自定义登录页面,必须指定登录url

loginProcessingUrl:指定用户名密码登录请求url,即UsernamePasswordAuthenticationFilter处理的请求

源码解读

一次顺畅的认证之旅

1. 未登录,浏览器访问根路径被重定向到登录页

服务启动后,在如下图示FilterChainProxy中打断点,浏览器新页面访问http://localhost:8035/

请求进入如下断点:

日志中可可以看到/请求进入:

放行直到nextFilter是SecurityContextPersistenceFilter时,进入该Filter

可以看到先从会话中提取SpringSecurityContext,放入本次请求的ThreadLocal对象中,用于后续处理,因此还未登录,因此这次提取的上下文对象是null,继续后续处理,点击进入chain.doFilter方法,可发现会重新进入FilterChainProxy:

同样断点放行,直到nextNextFilter是UsernamePasswordAuthenticationFilter时进入Filter:

进入requireAuthentication方法:

可发现当前URI是/,并不是/doLogin,因此返回false,然后将执行下一个Filter

放行断点直到AnonymousAuthenticationFilter,并进入:

可以看到构造的Authentication的authorizes是ROLE_ANONYMOUS,同时可以注意到details中有当前会话的sessionId;

放行断点并进入ExceptionTranslationFilter :

可以看到就是为了捕获后续过滤器的异常的!

放行断点并进入FilterSecurityInterceptor :

并进入beforeInvocation方法:

进入attemptAuthorization方法:

继续进入decide方法:

进入vote方法:

这符合我们的配置;是怎么判断的呢?肯定是根据配置。比如授权服务器处理/oauth/authorize接口需要authorities包含【ROLE_USER】,当用户未登录或者没有该权限时,这里肯定也返回拒绝!

点击下一步直到抛出异常:

debug点击下一步直到进入ExceptionTranslateFilter:

进入handleSpringSecurityException方法:

进入handleAccessDeniedException方法:

进入sendStartAuthentication(发送到开始认证的页面,即登录页):

进入commence方法:

断点放行进入FilterChainProxy,直到日志打印:Securing GET /login ,说明这是浏览器在请求登录页面!

2. 浏览器请求登录页面

和之前访问localhost:8035/的请求一样,还是会认证为一个匿名用户,然后进入FilterSecurityIntercepter进行授权校验:

然后在LoginController中打断点:

断点放行,可发现进入了LoginController:

断点放行,浏览器渲染登录页面

3. 用户名密码登录,成功后重定向到根路径

保持FilterChainProxy的断点,输入用户名root密码root点击登录按钮,请求进入断点:

日志也可看到当前请求是/doLogin;

断点放行,直到进入UsernamePasswordAuthenticationFilter:

这次requiresAuthentication方法判断为真了,因此进入认证方法:

可以看到其实进入的类是AbstractAuthencationProcessingFilter,就是各种认证处理过滤器的抽象父类;

进入attemptAuthentication后,就是子类具体实现了:

进入authenticate:

在如下图中标记断点,并放行到该断点:

可发现能处理UsernamePasswordAuthenticationToken的provider是DaoAuthenticationProvider,进入authenticate方法:

进入retrieveUser方法:

因为demo中自定义了InMemoryUserDetailService,因此会进入该Service:

查询返回User:

debug点击下一步,进入方法this.preAuthenticationChecks.check(user):

可返现校验了用户的状态;

点击下一步进入additionalAuthenticationChecks方法:

进行密码校验,通过后进入 this.postAuthenticationChecks.check(user):

debug点击下一步直到createSuccessAuthentication:

可以看到最终构造了一个Authentication对象,而且authenticated=true,这个方法可以注意下,当我们向构建登录态时,也可以构建这个对象,比如cookie单点登录设置登录态。

返回SuccessAuthentication后

debug点击下一步,回到抽象父类AbstractAuthenticationProcessingFilter:

可以执行方法successfulAuthentication,并且没有传入filterChain,也就是说肯定不会调用filterChain.doFilter(),因此UsernamePasswordAuthenticationFilter后面的Filter不会被执行了!

进入方法successfulAuthentication:

该方法中可以看到首先保存认证结果到SpringContext,这是为了使SecurityContextPersistenceFilter能够持久化

然后调用了successHandler方法,默认实现是SavedRequestAwareAuthenticationSuccessHandler,用户可以自定义覆盖这个默认实现,进入onAuthenticationSuccess方法:

进入onAuthenticationSuccess方法:

进入handle方法:

debug点击下一步,直到进入SecurityContextPersistenceFilter:

可以看到保存SpringContext到repo中!

保持FilterChainProxy断点:

debug放行,浏览器中可以看到doLogin重定向到localhost:8035/

4. 浏览器访问根路径,页面渲染成功

再次进入FilterChainProxy断点:

日志显示当前请求是 GET /

在根路径中打断点:

debug放行进入SecurityContextPersistenceFilter:

可以看到从repo中加载了前面认证成功后的SecurityContext,并放入SecurityContextHolder中;

因请求根路径,所以不会执行UsernamePasswordAuthenticationFilter的认证方法;

debug放行,进入AnonymousAuthenticationFilter :

因为SecurityContextHolder中已存在认证对象,因此不会构造匿名认证对象了;

debug放行,直到进入FilterSecurityInterceptor :

未抛出AccessDeniedException,则校验通过!

debug放行,请求将进入Controller:

debug放行,渲染页面,请求完成:

5. 流程图

 

密码错误源码分析

先进入登录页面,然后如下打断点:

当输入错误密码并提交,进入断点:

debug点击下一步,密码错误,抛出BadCredentialsException;点击下一步直到回到抽象父类异常捕获方法:

进入unsuccessfulAuthentication:

继续执行认证失败处理器,默认handler是SimpleUrlAuthenticationFailureHandler,进入:

重定向到登录页面!

相关内容

热门资讯

项目实战典型案例4——生产环境... 生产环境app打包导致不能自动升级的问题一:背景介绍问题背景:二...
奔奔mini-e怎么样-车主点... 今天给各位分享奔奔mini-e怎么样-车主点评-真实评价-口碑的知识,其中也会对奔奔mini10进行...
逍客逍客最新报价-图片-参数(... 本篇文章极速百科给大家谈谈逍客逍客最新报价-图片-参数,以及逍客2022款报价及参数对应的知识点,希...
全国违章查询在线查询_全国交通... 今天给各位分享全国违章查询在线查询_全国交通违章查询的知识,其中也会对全国违章查询网站在线进行解释,...
道路救援车拖车怎么收费-百度有... 今天给各位分享道路救援车拖车怎么收费-百度有驾的知识,其中也会对道路救援拖车费怎么算进行解释,如果能...
java 每日一练 (8) 文章目录1. 单选题2. 编程题 1. 单选题   1. 下列选项中关于 java 中 super ...
滁新高速淮南段发生一交通事故致... 本篇文章极速百科给大家谈谈滁新高速淮南段发生一交通事故致3人死亡,以及滁新高速淮南段拥堵对应的知识点...
快递投诉电话多少(极兔快递投诉... 今天给各位分享快递投诉电话多少的知识,其中也会对极兔快递投诉电话多少进行解释,如果能碰巧解决你现在面...
五羊本田小公主有几款?(五羊本... 本篇文章极速百科给大家谈谈五羊本田小公主有几款?,以及五羊本田小公主多少钱一台对应的知识点,希望对各...
红蓝buff是什么(红蓝buf... 本篇文章极速百科给大家谈谈红蓝buff是什么,以及红蓝buff是什么意思网络用语对应的知识点,希望对...
Gitee搭建个人博客(Bea... 目录一、引言二、博客模板选型 - Jekyll三、安装Jekyll环境3.1 安装Ruby3.2 安...
记一次磁盘扩容 起因 在使用firefly板子时,刷完固件发现根目录竟然只有3G,根本没...
开车撞死人怎么处理与赔偿?撞死... 今天给各位分享开车撞死人怎么处理与赔偿?撞死人协商最佳时间的知识,其中也会对开车撞死人要赔偿多少钱进...
ulzzang是什么牌子(ul... 本篇文章极速百科给大家谈谈ulzzang是什么牌子,以及ulzzang是什么牌子鞋对应的知识点,希望...
中国各重点城市豪车数量排名:北... 今天给各位分享中国各重点城市豪车数量排名:北上深广包揽前四!的知识,其中也会对中国地区豪车排行榜进行...
大分辨率数据集切割 前言:对于航拍、遥感影像数据集而言,此类数据集包含较多目标,...
叠信纸的四种方法(叠信纸的四种... 本篇文章极速百科给大家谈谈叠信纸的四种方法,以及叠信纸的四种方法a4多张图片对应的知识点,希望对各位...
记录Quartz在项目中的使用... 黑马传智健康项目中遇到的技术,感觉这个解决思路挺新颖的,就记录下来了。用...
Opengauss CLOG模... 上篇讲解了opengauss CLOG模块分区优化原理篇,本文将从源代码实现层面讨论具...
广汽三菱放大招2021款奕歌燃... 今天给各位分享广汽三菱放大招2021款奕歌燃情版上市售价16.78万元的知识,其中也会对广汽三菱弈歌...
科斯沃斯引擎(科斯沃d037)... 今天给各位分享科斯沃斯引擎的知识,其中也会对科斯沃d037进行解释,如果能碰巧解决你现在面临的问题,...
展望过去,想象未来,瑞航360... 今天给各位分享展望过去,想象未来,瑞航360全景2018新征程的知识,其中也会对瑞航lx188机型进...
考研数二第四讲 分段函数的复合... 分段函数的复合函数求分段函数的复合函数,这是考研高数中的一个重要考点。专升本的高数不考...
7座MPV车型推荐,7座MPV... 本篇文章极速百科给大家谈谈7座MPV车型推荐,7座MPV车型大全,以及7座mpv汽车大全2020对应...
支付宝怎么取消自动续费(苹果手... 今天给各位分享支付宝怎么取消自动续费的知识,其中也会对苹果手机支付宝怎么取消自动续费进行解释,如果能...
TH是什么意思(Things是... 本篇文章极速百科给大家谈谈TH是什么意思,以及Things是什么意思翻译对应的知识点,希望对各位有所...
上汽大众途观怎么样(上汽大众途... 本篇文章极速百科给大家谈谈上汽大众途观怎么样,以及上汽大众途观l2022版质量对应的知识点,希望对各...
solidworks转urdf... 是用solidworks成功导出了一次urdf,记录一下导出时各参数的说明。 基座的...
如何买火车票网上订票?网上买火... 今天给各位分享如何买火车票网上订票?网上买火车票怎么买的知识,其中也会对怎样买网上火车票进行解释,如...
加美机油质量怎么样?加美润滑油... 本篇文章极速百科给大家谈谈加美机油质量怎么样?加美润滑油排名第几,以及加美机油咋样对应的知识点,希望...