Spring Security身份认证Authentication

Authentication(身份认证框架)的架构

SecurityContextHolder

SpringSecurity会将用户的信息存储在SecurityContextHolder中,以下为SecurityContextHolder的模型
在这里插入图片描述
SecurityContextHolder中包含了SecurityContext对象,SecurityContext中包含了Authentication对象
Authentication对象的功能有两个:

  • 作为后续验证的入参
  • 获取当前验证通过的用户信息

Authentication包含三个属性:

  • principal:用户身份,如果是用户/密码认证,这个属性就是UserDetails实例
  • credentials:通常就是密码,在大多数情况下,在用户验证通过后就会被清除,以防密码泄露。
  • authorities:用户权限

AuthenticationManager

在这里插入图片描述

  • AuthenticationManager是用来实现身份认证的API接口,入参是Authentication,最常用的子类是ProviderManager
  • AuthenticationProvider是某种具体的认证实现,例如DaoAuthenticationProvider用来实现用户/密码认证,JwtAuthenticationProvider实现JWT Token认证
  • 支持多种类型AuthenticationProvider会注入到ProviderManager中,ProviderManager会根据Authentication的类型调用相应类型的AuthenticationProvider

AbstractAuthenticationProcessingFilter

在这里插入图片描述
AbstractAuthenticationProcessingFilter使用来进行用户认证的过滤器,会编排进SecurityFilterChain中,其处理流程为:

  1. 用户提交信息后,AbstractAuthenticationProcessingFilter 或从HttpServletRequest 提取信息并创建Authentication,Authentication的类型是由过滤器的类型决定的(AbstractAuthenticationProcessingFilter的子类),例如 UsernamePasswordAuthenticationFilter 创建 UsernamePasswordAuthenticationToken
  2. Authentication 被传入 the AuthenticationManager进行认证
  3. 如果认证失败
    (1)SecurityContextHolder 清除掉
    (2)RememberMeServices.loginFail 被调用,如果remember me 没有配置,则此方法为空方法
    (3)AuthenticationFailureHandler 被调用
  4. 认证成功
    SessionAuthenticationStrategy 被通知用户登陆.
    Authentication 存入 SecurityContextHolder. 之后 SecurityContextPersistenceFilter 会将SecurityContext存入HttpSession.
    RememberMeServices.loginSuccess 被调用,如果remember me没有配置,则改方法为空方法
    ApplicationEventPublisher 发布 InteractiveAuthenticationSuccessEvent.

用户密码验证 DaoAuthenticationProvider
DaoAuthenticationProvider实现了接口AuthenticationProvider,并且会使用UserDetailsService和PasswordEncoder来验证用户和密码
在这里插入图片描述

  1. 身份认证的过滤器会提取请求信息中的用户密码信息,传递UsernamePasswordAuthenticationToken(包含用户名和密码)对象至AuthenticationManager,其中ProviderManager是AuthenticationManager接口的实现类
  2. ProviderManager 中注册了DaoAuthenticationProvider(AuthenticationProvider接口的一个实现类,用于用户密码认证)
  3. DaoAuthenticationProvider 调用UserDetailsService获取存储的用户信息,得到UserDetails对象,UserDetails提供了对用户信息的基本操作
  4. DaoAuthenticationProvider 调用PasswordEncoder对传入的密码进行加密,并与上一步得到的UserDetails中的密码进行比较
  5. 验证通过后,用户信息会被存储于SecurityContextHolder中

关于密码存储

在介绍SpringSecurity认证机制之前,先说一些关于密码存储的内容。在SpringSecurity中PasswordEncoder接口用来提供单向加密机制,使密码存储更加安全。

密码存储的历史

在过去的多年时间里,密码存储机制进化了多次。最开始,密码就是明文文本存储,例如存储在数据库中,获取密码则需要使用数据库的用户与密码,因此人们则认为这种方式是安全的,但一些恶意用户却可以轻易的破解此方式,例如使用SQL注入等手段。

此后,密码存储前会通过单向Hash加密,例如SHA-256,当一个用户申请认证时,系统会对用户输入的密码进行hash加密,然后与系统存储的加密密码进行比较,如此系统只需要存储加密后的密文,这样即使密码泄露,也不会泄露真实的密码。不幸的是,黑客们发明了彩虹表(Rainbow Tables),通过查询彩虹表,很多密码都可以轻易的破解。

为了降低彩虹表的能力,安全专家建议使用加盐密码(salted passwords),在密码进行单向hash加密时,加入一些随机字符,这些随机字符被称为盐(salt)。

但近些年来,随着计算机硬件的快速发展,hash运算速度已提升为每秒十亿级,这意味着单向hash加密机制已经不再安全。现在更加推荐使用自适应的单向加密机制,自适应的单向加密机制可以配置一个工作因子(work factor),该因子会跟随硬件设备性能自行调整,使得加密过程所需要的时间在一个固定的值,这个值推荐在1秒钟左右,如此破解密码变得更加困难,常见的自适应加密机制包括bcrypt, PBKDF2, scrypt, 和 argon2

Spring Scurity中的密码存储机制

在Spring Security 5.0以前,默认的PasswordEncoder是NoOpPasswordEncoder,即明文密码,现在Spring Security的默认PasswordEncoder是DelegatingPasswordEncoder,DelegatingPasswordEncoder可以代理多种加密机制,其实例化过程如下:

public class DelegatingPasswordEncoderTest {
   
    public static void main(String[] args) {
   
        String idForEncode = "bcrypt";
        Map encoders = new HashMap<>();
        encoders.put(idForEncode, new BCryptPasswordEncoder());
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
        encoders.put("scrypt", new SCryptPasswordEncoder());
        encoders.put("sha256", new StandardPasswordEncoder());

        PasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(idForEncode, encoders);

        //对密码进行加密
        String encodedPassword = passwordEncoder.encode("password");
        System.out.println(encodedPassword); //{bcrypt}$2a$10$8nfdxLtGwvDu4MRI.CpCmOg56d7zNyq2xVJqaO4b.OPDFjlsu47Am

        //验证密码
        boolean res = passwordEncoder.matches("password", "{bcrypt}$2a$10$550FMm3qENbQtIWOa6qfsuqBftBF3BfVibViHv2ueQ3wGs45jEPWu");
        System.out.println("res = " + res); // res = true
    }
}

密码的存储格式为,其中{id}为对应的加密算法:

{id}encodedPassword

以下为对字符串"password"加密后的各种算法的结果:

{bcrypt}$2a$10$4lVeyJaX4NeUGLcAOG1KsuhguK30dwxMt9vO4woC.5elEC2xufWSu
{noop}password
{pbkdf2}8c3682ac6c8a7285060cc984fe3cf6da2af1a98410ad244b8b2b90fb90f60665c437a5cff05682e3
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
{sha256}9b050796bcdab7d9f9009669fac770584071e4057f4edae723e28096fe21910e7e95420647a2749f

用户/密码认证

根据HttpRequest提取用户密码的方式区分

FormLogin 页面表单登陆

默认页面登陆认证

在Springboot中引入Spring Security依赖

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值