springSecurity源码执行过程分析

springSecurity源码执行过程分析

1.SpringBoot初始化

springoot自动初始化会向spring容器中注册 springSecurityFilterChainfilter

以下是springboot autoconfiguration 的自动配置

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
1.SecurityAutoConfiguration

导入如下的配置类

@Import({SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, SecurityDataConfiguration.class})
  • 1.SpringBootWebSecurityConfiguration

    配置了DefaultConfigurerAdapter

  • 2.WebSecurityEnablerConfiguration

    使用@EnableWebSecurity注解,开启了web的安全配置

  • 3.SecurityDataConfiguration 配置data相关,目前不太熟悉,先不去研究

2.UserDetailsServiceAutoConfiguration

配置userService ,但是存在很多条件,默认情况下,我们在二次开发中都是重新定制这个userService,导致当前类的自动配置不能生效

3.SecurityFilterAutoConfiguration

对于容器中如果存在springSecurityFilterChain这个bean,就对当前bean产生委托对象DelegatingFilterProxyRegistrationBean,并注册到容器中

下面详细看以下 @EnableWebSecurity内部作了什么

同样进行了导入,导入的类如下

@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class})

同时使用了@EnableGlobalAuthentication注解

  • 1.WebSecurityConfiguration

    配置了springSecurityFilterChain这个过滤器

    收集配置的SecurityConfigurer

  • 2.配置了SpringWebMvcImportSelector,向容器内部导入了WebMvcSecurityConfiguration,该类向容器中导入了三个参数处理器,分别用来处理不同的注解

    AuthenticationPrincipalArgumentResolver:用来处理@AuthenticationPrincipal的参数注解,可以直接获得登陆的信息

    CurrentSecurityContextArgumentResolver:用来处理@CurrentSecurityContext的参数注解 ,可以直接获得安全上下文的相关信息

    CsrfTokenArgumentResolver:可以通过Spring MVC参数解析当前的CsrfToken

  • OAuth2ImportSelector:和oAuth2相关的配置,暂不了解

下面看一下EnableGlobalAuthentication作了什么事情,

当前注解导入了AuthenticationConfiguration,其中主要作了如下的工作

  • 1.创建了 authenticationManagerBuilder

    同时设置了默认的密码策略是BCryptPasswordEncoder

  • 2.创建了GlobalAuthenticationConfigurerAdapter

  • 3.创建了InitializeUserDetailsBeanManagerConfigurer

    当前类在初始化的时候,会对authenticationManagerBuilder进行相关配置,springSecurity为了解耦数据层,内部提供了UserService用于开发者 自己实现,在当前类的init函数中,为了方便理解,我截了一张图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ejEn8A9j-1682560068182)(assets/image-20230426105753258.png)]

所以从这里我们能够看出,对于授权 的流程,使用的是AuthticationManager,同时默认使用的是DaoAuthenticationProvider,对于UserService和PasswordEncoder会从容器中去取。

  • 4.创建了InitializeAuthenticationProviderBeanManagerConfigurer

    当前类和上面的过程存在一点差异,看名字我们应该也能看的出来,当前是对 AuthenticationProvider进行定制的过程,从上面来看,provider充当了 授权的核心过程,为了方便还是截图看下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vu7B1v8X-1682560068182)(assets/image-20230426110510664.png)]

这里请不要怀疑,这里为什么都没有从spring容器中取userSerivice等相关bean,这里,我是这么理解的,既然你都要对provider进行重写了,在构造过程中就能对Suserervice进行setter。

2.springSecurity中常用的filter以及对应的作用

下面是运行调试的截图,根据不同的httpSecurity的配置,如下可能会不同,下面在配置章节会详细去说,当前阶段不做分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8w9O5GF-1682560068183)(assets/image-20230426134347299.png)]

过滤器作用核心触发条件
WebAsyncManagerIntegrationFilter为WebAsyncManager提供异步回调的Security上下文环境
SecurityContextPersistenceFilter持久化上下文信息,提供了实现有基于HttpSession的,原因是http的无状态化
HeaderWriterFilter添加请求头
LogoutFilter处理/logout请求,回调LogoutSuccessHandler
UsernamePasswordAuthenticationFilter处理/login请求,调用内部认证进行登陆操作
RequestCacheAwareFilter请求缓存,添加请求头,以及相关参数处理,格式化
SecurityContextHolderAwareRequestFilter提供对Servlet3的支持,包括login,logout接口的支持
AnonymousAuthenticationFilter创建一个默认的Authentication保存到上下文中
SessionManagementFilter会话管理,管理当前会话数量
ExceptionTranslationFilter异常处理,对于整个filter产生的异常进行拦截处理
FilterSecurityInterceptor用来进行访问权限校验的核心过滤器,如果没有通过,会被ExceptionTranslationFilter拦截,通过不同的异常进行不同的错误处理

3.登陆流程

对于使用springSecurity进行登陆的开发,我们需要配置表单登陆

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNNwGhpz-1682560068183)(assets/image-20230426152444056.png)]

这里使用了formLogin,实际上就是注册了 UsernamePasswordAuthenticationFilter,从而实现了登陆的操作,下面我截核心代码

在这里插入图片描述

其中按照图所说,其中的

 return this.getAuthenticationManager().authenticate(authRequest);

就是调用springboot自动创建的AuthenticationManager进行处理,具体的流程不再叙述,使用图式表示以下

AuthenticationManager---->DaoAuthenticationProvider—>UserDetailService

最终 UserDetailService 返回的值会被封装到 如下的结构中

在这里插入图片描述

当然以上都是默认的处理逻辑。具体执行过程按照 整个项目的定制化程度而定

4.鉴权过程

按照上面的说法,我们对鉴权给出了核心的过滤器FilterSecurityInterceptor,下面是核心代码

在这里插入图片描述

内部通过 accessDesicionManager来决定当前接口的访问是 通过还是拒绝的,如果没有通过会抛出 Exception,上面也说了,对于异常,都是会被

ExceptionTranslationFilter 所接收到,核心处理异常的代码图下

在这里插入图片描述

对于鉴权错误的exception,默认情况下,会清空当前登陆的上下文信息,同时响应403访问被拒绝

当然如果你配置了表单登陆,会被LoginUrlAuthenticationEntryPoint处理

在这里插入图片描述

按照上面截图的逻辑,默认情况下,如果强制forward,并且强制https,会强制定向到https的地址上去,反之就定向到表单登陆配置的登陆页面

如果你是前后端分离的应用,按照上面的描述,定制一个认证的进入点来替代默认的进入点,返回json数据,可能更加符合要求

5.全局方法安全配置

使用全局方法安全,只需要在启动类上配置如下

@EnableGlobalMethodSecurity

需要注意的是,如果你使用上面的注解,需要开启如下两种的其中一种,否则会导致报错

@EnableGlobalMethodSecurity(prePostEnabled = true)
//或
@EnableGlobalMethodSecurity(securedEnabled  = true)    
1. 初始化过程

根据源代码我们发现它向spring容器中添加了GlobalMethodSecurityConfiguration的配置,那么先看下这个类的作用

  • 1.根据开启的安全特性,注册了一个方法安全的拦截器MethodSecurityInterceptor,这里十分核心
  • 2.创建了PreInvocationAuthorizationAdvice前置调用通知

按照上面的分析过程,我们知道,方法的拦截处理逻辑使用过aop实现的,所以该校验的执行过程是最后的,也就是在 上面我们提到的过滤器之后。

对于上面的两种情况,我们分别分析

2.PrePost开启的处理流程

按照上面的理解,核心是MethodSecurityInterceptor,其中大量的实现是父类实现的,下面是核心代码

在这里插入图片描述

最终还是交给了accessDecisionManager来处理的,这个和我们上面提到的流程是一样的,不再过多叙述

在这里插入图片描述

从上面我们看到进行了Voter,根据Vote的结果,来决定是否有权限访问,那么

在这里插入图片描述

最终会找到 ExpressionBasedPreInvocationAdvice类,找到AuthorizeExpression 来进行权限的校验,这里最终调用的 是MethodSecurityExpressionRoot该类用来处理@PreAuthorize(“hasAuthority(‘ROLE_ADMIN’)”)的表达式,其中的hasAuthority方法直接对应当前类的方法,当然,我们也可以定制这一套处理逻辑,例如如下

在这里插入图片描述

3.secured开启的处理流程

其本质和上面是一致的,对于voter来说,不同投票器的支持情况不同,@Secured注解直接编写Role_会被RoleVoter匹配上,进行权限的校验,具体voter已经在下面进行了说明

4.总结

httpSecurity配置和方法的配置是相辅相成的,只是方法校验的执行时间是更靠后的,如果httpSecurity没有配置拦截或则直接permitAll(),方法上面如果存在注解,依然访问会没有权限。具体怎么配置要看自己的项目

6.关于Voter

上面我们说了最终确定是否存在访问权限的是Voter,那么下面详细看下Security提供的几个Voter类,来看具体的投票逻辑

说明
RoleVoter角色投票,根据你配置的权限,通过查找当前用户是否具有当前权限的投票人,判断方法为循环比较
WebExpressionVoter提供的webb表达式的支持,就是spel ,相关函数使用的是DefaultWebSecurityExpressionHandler
Jsr250Voter提供对Jsr205 校验的支持,具体的注解将在下面进行说明
AuthenticatedVoter区分匿名用户,认证过的用户和remember-me认证的用户,进行投票
PreInvocationAuthorizationAdviceVoter提供对PreAuthorize注解的支持

7.jsr250标准

spring security方法安全同样提供了对jsr250的支持,默认情况是关闭的,如果需要使用,请使用如下代码开启

@EnableGlobalMethodSecurity(jsr250Enabled = true)

开启后,会使用Jsr250Voter进行投票

1.注解以及作用
注解作用作用域
RolesAllowed判断是否具有访问权限方法或类
DenyAll全部拒绝访问方法或类
PermitAll全部允许访问方法或类
DeclareRoles暂时发现没有用!方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值