jjzjj

springboot3 security 从始至终--02 PasswordEncoder

wanzhouyi 2023-04-16 原文

接下来几个章节,将逐个介绍身份验证流程中主要接口

接口 描述
UserDetails 代表SpringSecurity所看到的用户
GrantedAuthority 定义应用程序目的范围内允许用户执行的操作(读、写、删除等)
UserDetailsService 表示用于按用户名检索用户详细信息的对象
UserDetailsManager 一个较为特殊的UserDetailsService接口。除了按用户名检索用户外,它还可以用于更改用户集合或特定用户
PasswordEncoder 指定如何对密码进行加密或哈希化,以及检查给定的已编码字符串是由与明文密码匹配

本文将一起学习相对独立的PasswordEncoder。

一、先看看定义

package org.springframework.security.crypto.password;

/**
 * Service interface for encoding passwords.
 *
 * The preferred implementation is {@code BCryptPasswordEncoder}.
 *
 * @author Keith Donald
 */
public interface PasswordEncoder {

	/**
	 * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
	 * greater hash combined with an 8-byte or greater randomly generated salt.
	 */
	String encode(CharSequence rawPassword);

	/**
	 * Verify the encoded password obtained from storage matches the submitted raw
	 * password after it too is encoded. Returns true if the passwords match, false if
	 * they do not. The stored password itself is never decoded.
	 * @param rawPassword the raw password to encode and match
	 * @param encodedPassword the encoded password from storage to compare with
	 * @return true if the raw password, after encoding, matches the encoded password from
	 * storage
	 */
	boolean matches(CharSequence rawPassword, String encodedPassword);

	/**
	 * Returns true if the encoded password should be encoded again for better security,
	 * else false. The default implementation always returns false.
	 * @param encodedPassword the encoded password to check
	 * @return true if the encoded password should be encoded again for better security,
	 * else false.
	 */
	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}

}

该接口定义了两个抽象方法,其中几个具有默认实现。在处理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 的实例:

PasswordEncoder passwordEncoder =  
   PasswordEncoderFactories.createDelegatingPasswordEncoder();

当然也可以选择其它实例:

String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("sha256", new StandardPasswordEncoder());

PasswordEncoder passwordEncoder =
    new DelegatingPasswordEncoder(idForEncode, encoders);

3.2 使用自定义的的PasswordEncoder

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

3.3 注入PasswordEncoder

在开发中,我们将 BCryptPasswordEncoder 的实例放入Spring容器即可

//密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

有关springboot3 security 从始至终--02 PasswordEncoder的更多相关文章

  1. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  2. 牛客网专项练习30天Pytnon篇第02天 - 2

    1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析:    在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1:    print(k)k=k/2A.1000 B.10C.11D.9解析:    按照题意每次循环K/2,直到K值小于等

  3. springboot定时任务 - 2

    如果您希望在Spring中启用定时任务功能,则需要在主类上添加 @EnableScheduling 注解。这样Spring才会扫描 @Scheduled 注解并执行定时任务。在大多数情况下,只需要在主类上添加 @EnableScheduling 注解即可,不需要在Service层或其他类中再次添加。以下是一个示例,演示如何在SpringBoot中启用定时任务功能:@SpringBootApplication@EnableSchedulingpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.ru

  4. 基于SpringBoot的线上日志阅读器 - 2

    软件特点部署后能通过浏览器查看线上日志。支持Linux、Windows服务器。采用随机读取的方式,支持大文件的读取。支持实时打印新增的日志(类终端)。支持日志搜索。使用手册基本页面配置路径配置日志所在的目录,配置后按回车键生效,下拉框选择日志名称。选择日志后点击生效,即可加载日志。windows路径E:\java\project\log-view\logslinux路径/usr/local/XX历史模式历史模式下,不会读取新增的日志。针对历史文件可以分页读取,配置分页大小、跳转。历史模式下,支持根据关键词搜索。目前搜索引擎使用的是jdk自带类库,搜索速度相对较低,优点是比较简单。2G日志全文搜

  5. springboot使用validator进行参数校验 - 2

    1.依赖导入org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-validation2.validation常用注解@Null被注释的元素必须为null@NotNull被注释的元素不能为null,可以为空字符串@AssertTrue被注释的元素必须为true@AssertFalse被注释的元素必须为false@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值@D

  6. Spring Security 6.0系列【32】授权服务器篇之默认过滤器 - 2

    有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N

  7. ruby-on-rails - 使用 secure_random stub rspec 中的随机值 - 2

    我正在尝试为我的gem编写规范,它生成otp并将其保存在数据库中。现在我正在为它编写规范。所以基本上我有三种方法generate_otp!、regenerate_otp!、verify_otp(otp)。generate_otp!的作用是调用包含三个变量的方法generate_otpotp_code-基本上是使用secure_random生成的随机值otp_verified-一个bool值,用于设置otp是否已验证的状态otp_expiry_time-设置otp的到期时间,可以由Rails应用在配置中设置。这三个也是我的数据库的列。在generate_otp之后,我正在调用active

  8. 停车系统源码-基于springboot+uniapp开源项目 - 2

    Iparking停车收费管理系统-可商用介绍Iparking是一款基于springBoot的停车收费管理系统,支持封闭车场和路边车场,支持微信支付宝多种支付渠道,支持多种硬件,涵盖了停车场管理系统的所有基础功能。技术栈Springboot,MybatisPlus,Beetl,Mysql,Redis,RabbitMQ,UniApp功能云端功能序号模块功能描述1系统管理菜单管理配置系统菜单2系统管理组织管理管理组织机构3系统管理角色管理配置系统角色,包含数据权限和功能权限配置4系统管理用户管理管理后台用户5系统管理租户管理多租户管理6系统管理公众号配置租户公众号配置7系统管理操作日志审计日志8系统

  9. ruby - 使用 ruby​​ 应用程序时出现 remove_entry_secure 错误 - 2

    我正在尝试使用docsplit将PDF文件拆分为图像。但看来我的ruby​​安装有问题。我每次都会收到以下错误:/usr/lib/ruby/1.8/fileutils.rb:694:in`remove_entry_secure':parentdirectoryisworldwritable这是完整的命令行输出:$docsplitimagespdf-test.pdf/usr/lib/ruby/1.8/fileutils.rb:694:in`remove_entry_secure':parentdirectoryisworldwritable,FileUtils#remove_entry_

  10. Ruby:为什么 1.025.round(2) 四舍五入为 1.02? - 2

    据我了解.round()-ruby中的功能将小数向上舍入,最后一个有效数字是5?例如1.5.round(0)#=>2(OK)但为什么1.025.round(2)#=>1.02而不是我期望的1.03?irb(main):037:0>1.025.round(2)=>1.02我该怎么做才能解决这个问题? 最佳答案 这与最后一位数字为5无关,与将十进制值转换为double浮点值有关。http://en.wikipedia.org/wiki/Double_precision_floating-point_format基本上,十进制数必须以有限

随机推荐