SpringBoot Spring Security 核心组件 认证流程 用户权限信息获取详细讲解

本文详细介绍了SpringSecurity框架中的核心组件,如SecurityContextHolder的作用,Authentication对象的结构,以及UserDetailsService接口的使用。涵盖了认证流程,包括用户名和密码验证、权限信息获取、用户身份验证等关键步骤。
摘要由CSDN通过智能技术生成

SpringBoot Spring Security 核心组件 认证流程 用户权限信息获取详细讲解
前言
Spring Security 是一个安全框架, 可以简单地认为 Spring Security 是放在用户和 Spring 应用之间的一个安全屏障, 每一个 web 请求都先要经过 Spring Security 进行 Authenticate 和 Authoration 验证
在这里插入图片描述

核心组件 SecurityContextHolder

SecurityContextHolder它持有的是安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权等等,这些都被保存在SecurityContextHolder中。SecurityContextHolder默认使用ThreadLocal 策略来存储认证信息。看到ThreadLocal 也就意味着,这是一种与线程绑定的策略。在web环境下,Spring Security在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息

看源码他有静态方法

SecurityContext
安全上下文,主要持有Authentication对象,如果用户未鉴权,那Authentication对象将会是空的。看源码可知

package org.springframework.security.core.context;import java.io.Serializable;
import org.springframework.security.core.Authentication;public interface SecurityContext extends Serializable {
    Authentication getAuthentication();void setAuthentication(Authentication var1);
}
```java
``

# `Authentication

鉴权对象,该对象主要包含了用户的详细信息(UserDetails)和用户鉴权时所需要的信息,如用户提交的用户名密码、Remember-me Token,或者digest hash值等,按不同鉴权方式使用不同的Authentication实现
看源码可知道

Authentication是spring security包中的接口,直接继承自Principal类,而Principal是位于java.security包中的。可以见得,Authentication在spring security中是最高级别的身份/认证的抽象。由这个顶级接口,我们可以得到用户拥有的权限信息列表,密码,用户细节信息,用户身份信息,认证信息。

getAuthorties(),权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。

getCredentials(),密码信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。

getDetails(),细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值。

getPrincipal(),敲黑板!!!最重要的身份信息,大部分情况下返回的是UserDetails接口的实现类,也是框架中的常用接口之一

注意GrantedAuthority该接口表示了当前用户所拥有的权限(或者角色)信息。这些信息由授权负责对象AccessDecisionManager来使用,并决定最终用户是否可以访问某资源(URL或方法调用或域对象)。鉴权时并不会使用到该对象

## UserDetails

这个接口规范了用户详细信息所拥有的字段,譬如用户名、密码、账号是否过期、是否锁定等。在Spring Security中,获取当前登录的用户的信息,一般情况是需要在这个接口上面进行扩展,用来对接自己系统的用户

看源码可知package org.springframework.security.core.userdetails;import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
}
UserDetailsService
这个接口只提供一个接口loadUserByUsername(String username),这个接口非常重要,一般情况我们都是通过扩展这个接口来显示获取我们的用户信息,用户登陆时传递的用户名和密码也是通过这里这查找出来的用户名和密码进行校验,但是真正的校验不在这里,而是由AuthenticationManager以及AuthenticationProvider负责的,需要强调的是,如果用户不存在,不应返回NULL,而要抛出异常UsernameNotFoundException

Spring Security安全身份认证流程原理
用户名和密码被过滤器获取到,封装成Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。

AuthenticationManager 身份管理器负责验证这个Authentication

认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例。

SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication,通过SecurityContextHolder.getContext().setAuthentication()方法,设置到其中。

初次接触Spring Security的朋友相信会被AuthenticationManagerProviderManagerAuthenticationProvider …这么多相似的Spring认证类搞得晕头转向,但只要稍微梳理一下就可以理解清楚它们的联系和设计者的用意。

AuthenticationManager(接口)是认证相关的核心接口,也是发起认证的出发点,因为在实际需求中,我们可能会允许用户使用用户名+密码登录,同时允许用户使用邮箱+密码,手机号码+密码登录,甚至,可能允许用户使用指纹登录(还有这样的操作?没想到吧),所以说AuthenticationManager一般不直接认证,

AuthenticationManager接口的常用实现类ProviderManager 内部会维护一个List列表,存放多种认证方式,实际上这是委托者模式的应用(Delegate)。

也就是说,核心的认证入口始终只有一个:AuthenticationManager,不同的认证方式:用户名+密码(UsernamePasswordAuthenticationToken),邮箱+密码,手机号码+密码登录则对应了三个AuthenticationProvider。这样一来就好理解多了
## 全局上下文获取
由于获取当前用户的用户名是一种比较常见的需求,其实 Spring SecurityAuthentication 中的实现类中已经为我们做了相关实现,所以获取当前用户的用户名有如下更简单的方式
```获取当前登录用户的 UserDetails 实例,然后再转换成自定义的用户实体类 User,这样便能获取用户的 ID 等信息

```java
@RestController
public class HelloController {
 
    @GetMapping("/hello")
    public String hello() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User user = (User)principal;
        return "当前登录用户信息:" + user.toString();
    }
}

SpirngSecurity创建springSecurityFilterChain的详细过程1、DelegatingFilterProxy

2、springSecurityFilterChain
3、SpringBoot是如何找到SpringSecurity的配置入口SecurityAutoConfiguration
4、SpringSecurity处理请求的基本流程
另外在自动配置类SecurityAutoConfiguration中,引入了配置类WebSecurityEnablerConfiguration
在这里插入图片描述
在这里插入图片描述还是这个@EnableWebSecurity注解,上篇文章中只是简单的介绍了一下其引入的WebSecurityConfiguration配置类,并且在WebSecurityConfiguration配置类中看到了springSecurityFilterChain的bean定义,下面来看下@EnableGlobalAuthentication注解中有什么内容
在这里插入图片描述可以@EnableGlobalAuthentication注解的主要工作其实又是由AuthenticationConfiguration配置类来完成的
可以看到AuthenticationConfiguration又导入了另一个配置类ObjectPostProcessorConfiguration
在这里插入图片描述在这里插入图片描述下面先来简单看下这两个配置类中都有哪些bean,混个眼熟。

一、ObjectPostProcessorConfiguration
post-processor在编程中很常见,可以理解为一个后置处理器。当然前置处理器就是pre-processor。这个配置类中只配置了一个bean:
自动传入的bean是一个AutowireCapableBeanFactory类型的BeanFactory,顾名思义就是具有自动装配能力的beanFactory。

ObjectPostProcessorConfiguration中只是通过AutowireCapableBeanFactory生成了一个名为objectPostProcessor的bean,并没有其他逻辑。

二、AuthenticationConfiguration
authenticationConfiguration配置类中存在四个bean,如下图所示
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述列出上面的bean都是为了混个脸熟,先只需要知道这些bean的存在就行,后面会用到。通过上一篇的debug分析,我们可以知道SpringSecurity框架的入口就是springSecurityFilterChain的doFilter方法。要是想熟悉整个验证流程,则最好从这个方法开始一步步深入。不过在查看doFilter方法之前,先来看下springSecurityFilterChain的初始化细节。
三、springSecurityFilterChain的bean初始化
在这里插入图片描述
1、webSecurityConfigurers

初始化bean的第一步用到了这个webSecurityConfigurers的类,在当前类中搜索这个变量
在这里插入图片描述
可以发现这是个SecurityConfigurer<Filter, WebSecurity>类型的List,来看下它是在哪初始化的。在当前配置类中发现了下面这个方法,@Autowired注解自动注入了两个bean,分别是objectPostProcessor和webSecurityConfigurers。objectPostProcessor在本文最开始的时候我们已经看到了,webSecurityConfigurers是在初始化的呢?
不过我们可以发现参数之前有个@Value注解:
在这里插入图片描述
这个注解的意思是,webSecurityConfigurers是通过调用beanName为autowiredWebSecurityConfigurersIgnoreParents的bean的getWebSecurityConfigurers()获得的。而这个bean恰好在当前配置类中有定义,来了解下其内部逻辑

在这里插入图片描述
我们可以看到getWebSecurityConfigurers方法确实存在
在这里插入图片描述
通过代码我们可以得知,webSecurityConfigurers其实就是spring上下文中所有WebSecurityConfigurer类型的bean的集合
在这里插入图片描述所以webSecurityConfigurers默认就是List<>{ DefaultConfigurerAdapter },不过通过源码的阅读我们可以得到一个结论,如果我们继承webSecurityConfigurer接口,定义自己的配置类并且注册成bean,也会被SpringSecurity加载
2、webSecurity
webSecurity的初始化也是在注入webSecurityConfigurers时进行的,其中用到了objectPostProcessor的postProcess方法。
在这里插入图片描述
由上面源码得知postProcess的作用其实就是将webSecurity对象创建成一个bean注册到spring上下文中。目前已经可以得知这个objectPostProcessor是干什么的了,就是用来动态生成bean的,而且动态生成bean的同时还能够提供bean生命周期中post相关的操作的支持。读到这可以得出一个结论,webSecurity类型的bean是在处理webSecurityConfigurers时动态生成的。
webSecurityConfigurers的下一步处理是@Order注解,上面这段代码的意思说明配置类的@Order注解有两个作用,一是用来排序,二是用来表示唯一性。
3、springSecurityFilterChain的创建
webSecurityConfigurers的加载和处理,webSecurity实例的创建在上面已经分析了。最后一步就是通过webSecurity对象创建springSecurityFilterChain了,build方法也是继承于AbstractSecurityBuilder抽象类的。
1、SpringSecurity上下文中默认的AuthenticationManger是ProviderManger

2、SpringSecurity上下文中默认的Provider是DaoAuthenticationProvider

3、SpringSecurity上下文中默认的UserService是InMemoryUserService

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值