springboot3 security 从始至终--02 PasswordEncoder

[复制链接]
发表于 2023-2-7 23:52:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
接下来几个章节,将逐个介绍身份验证流程中主要接口
接口描述UserDetails代表SpringSecurity所看到的用户GrantedAuthority定义应用程序目的范围内允许用户执行的操作(读、写、删除等)UserDetailsService表示用于按用户名检索用户详细信息的对象UserDetailsManager一个较为特殊的UserDetailsService接口。除了按用户名检索用户外,它还可以用于更改用户集合或特定用户PasswordEncoder指定如何对密码进行加密或哈希化,以及检查给定的已编码字符串是由与明文密码匹配本文将一起学习相对独立的PasswordEncoder。
一、先看看定义
  1. package org.springframework.security.crypto.password;
  2. /**
  3. * Service interface for encoding passwords.
  4. *
  5. * The preferred implementation is {@code BCryptPasswordEncoder}.
  6. *
  7. * @author Keith Donald
  8. */
  9. public interface PasswordEncoder {
  10.         /**
  11.          * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
  12.          * greater hash combined with an 8-byte or greater randomly generated salt.
  13.          */
  14.         String encode(CharSequence rawPassword);
  15.         /**
  16.          * Verify the encoded password obtained from storage matches the submitted raw
  17.          * password after it too is encoded. Returns true if the passwords match, false if
  18.          * they do not. The stored password itself is never decoded.
  19.          * @param rawPassword the raw password to encode and match
  20.          * @param encodedPassword the encoded password from storage to compare with
  21.          * @return true if the raw password, after encoding, matches the encoded password from
  22.          * storage
  23.          */
  24.         boolean matches(CharSequence rawPassword, String encodedPassword);
  25.         /**
  26.          * Returns true if the encoded password should be encoded again for better security,
  27.          * else false. The default implementation always returns false.
  28.          * @param encodedPassword the encoded password to check
  29.          * @return true if the encoded password should be encoded again for better security,
  30.          * else false.
  31.          */
  32.         default boolean upgradeEncoding(String encodedPassword) {
  33.                 return false;
  34.         }
  35. }
复制代码
该接口定义了两个抽象方法,其中几个具有默认实现。在处理PasswordEncoder实现时,最常见的是抽象的encode()和matches()方法。
encode(CharSequence rawPassword)方法的目的是返回所提供字符串的转换。就SpringSecurity功能而言,它用于为指定密码提供加密或哈希化。
之后可以使用matches(CharSequence rawPassword, String encodedPassword)方法检查已编码的字符串是否与演示密码匹配。可以在身份验证过程中使用matches()方法根据一组已知凭据来检验所提供的的密码。
第三个方法被称为upgradeEncoding(String encodedPassword),在接口中默认设置为false。如果重写它以返回true,那么为了更好的安全性,将重新对已编码的密码进行编码(不推荐这种方式)。
二、接口的作用

一般而言,系统并不以明文形式管理密码,因此密码通常要经过某种转换,这使得读取和窃取密码变得较为困难。为此,SpringSecurity定义了一个单独的接口。
实现这个接口是为了告知SpringSecurity如何验证用户的密码。在身份验证过程中,PasswordEncoder会判定密码是否有效。每个系统都会存储以某种方式编码过的密码。最好把密码哈希化存储起来,这样别人就不会读到明文密码了。PasswordEncoder还可以对密码进行编码。接口声明的encode()和matches()方式实际上是对其职责的定义。这两个方法都是同一接口的一部分,因此它们紧密相连。应用程序对密码进行编码的方式与验证密码的方式相关。
三、实现PasswordEncoder

3.1 使用默认的PasswordEncoder

在 Spring Security 5.0 之前,PasswordEncoder 默认值是 NoOpPasswordEncoder,这需要纯文本密码。 但现在您可能期望现在的默认值类似于BCryptPasswordEncoder。但是,这忽略了三个现实世界的问题:

  • 许多应用程序使用无法轻松迁移的旧密码编码。
  • 密码存储的最佳做法将再次更改。
  • 作为一个框架,Spring 安全性不能经常进行重大更改。
相反,Spring Security 引入了 DelegatingPasswordEncoder,它通过以下方式解决了所有问题:

  • 确保使用当前密码存储建议对密码进行编码
  • 允许以现代和传统格式验证密码
  • 允许将来升级编码
您可以使用PasswordEncoderFactories轻松构造DelegatingPasswordEncoder 的实例:
  1. PasswordEncoder passwordEncoder =  
  2.    PasswordEncoderFactories.createDelegatingPasswordEncoder();
复制代码
当然也可以选择其它实例:
  1. String idForEncode = "bcrypt";
  2. Map encoders = new HashMap<>();
  3. encoders.put(idForEncode, new BCryptPasswordEncoder());
  4. encoders.put("noop", NoOpPasswordEncoder.getInstance());
  5. encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
  6. encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
  7. encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
  8. encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
  9. encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
  10. encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
  11. encoders.put("sha256", new StandardPasswordEncoder());
  12. PasswordEncoder passwordEncoder =
  13.     new DelegatingPasswordEncoder(idForEncode, encoders);
复制代码
3.2 使用自定义的的PasswordEncoder

通常情况下,使用spring boot security自带的password encoder已经足够满足使用场景了。笔者也不建议自己实现password encoder。
3.3 注入PasswordEncoder

在开发中,我们将 BCryptPasswordEncoder 的实例放入Spring容器即可
  1. //密码编码器
  2. @Bean
  3. public PasswordEncoder passwordEncoder() {
  4.     return new BCryptPasswordEncoder();
  5. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
继续阅读请点击广告
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表