如何覆盖通过PasswordEncoderFactories创建的默认BCryptPasswordEncoder?

问题描述 投票:0回答:1

我知道在 Spring Security 中会出现以下情况:

There was an unexpected error (type=Internal Server Error, status=500).
There is no PasswordEncoder mapped for the id "null"
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

解决方案是定义一个

PasswordEncoder
。为了简单起见,可以定义以下内容:

@Bean
PasswordEncoder encoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

现在,在幕后如何定义

createDelegatingPasswordEncoder()
方法(到目前为止,直到 Spring Security 5.4.2 为止)(有关更多详细信息,请参阅 PasswordEncoderFactories 类):

@SuppressWarnings("deprecation")
public static PasswordEncoder createDelegatingPasswordEncoder() {
    String encodingId = "bcrypt";
    Map<String, PasswordEncoder> encoders = new HashMap<>();
    encoders.put(encodingId, new BCryptPasswordEncoder());
    encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
    encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
    encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
    encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
    encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());
    encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
    encoders.put("SHA-256",
            new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
    encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
    encoders.put("argon2", new Argon2PasswordEncoder());
    return new DelegatingPasswordEncoder(encodingId, encoders);
}

现在关于 BCryptPasswordEncoder 类,它可以使用一些默认值,例如:

    版本:
  • $2a
    
    
  • 强度:
  • 10
    
    
如果声明以下内容会发生什么:

@Bean PasswordEncoder bcryptEncoder() { return new BCryptPasswordEncoder(BCryptVersion.$2Y, 12); }
如何将使用 

custom BCryptPasswordEncoder

 创建的 
default BCryptPasswordEncoder
 添加或覆盖到默认设置中?我想保留所有其他默认值

注意:在 PasswordEncoderFactories 类(对于 createDelegatingPasswordEncoder

 方法)中,
DelegatingPasswordEncoder 类在幕后使用。该类也不提供重写方法。

spring-security bcrypt
1个回答
7
投票
如果您正在创建

新应用程序,您很可能不需要DelegatingPasswordEncoder

,而应该使用自适应单向功能密码编码器,例如
BCryptPasswordEncoder

为此,您可以将

BCryptPasswordEncoder

 公开为 bean。

@Bean PasswordEncoder bcryptEncoder() { return new BCryptPasswordEncoder(BCryptVersion.$2Y, 12); }
然后,当用户注册时,您可以使用 

BCryptPasswordEncoder

 对其密码进行编码,然后将其保存到数据存储中。例如:

UserDetails userDetails = User .withUsername(username) .password(bcryptEncoder.encode(password)) .roles("USER") .build();
如果您要迁移

现有应用程序,则DelegatingPasswordEncoder

很有用。

DelegatingPasswordEncoder

 允许验证多种格式的密码。它使用前缀 ID(例如 
{bcrypt}
)来查找应使用哪个 
PasswordEncoder

考虑使用明文密码的遗留应用程序。

要迁移应用程序,您可以在明文密码前添加
{noop}

 前缀,并使用 
DelegatingPasswordEncoder
,如下所示:

@Bean public PasswordEncoder delegatingPasswordEncoder() { Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put("bcrypt", new BCryptPasswordEncoder(BCryptVersion.$2Y, 12)); encoders.put("noop", NoOpPasswordEncoder.getInstance()); return new DelegatingPasswordEncoder("bcrypt", encoders); }

DelegatingPasswordEncoder

将使用
BCryptPasswordEncoder
对任何新创建的密码进行编码和验证,同时仍然能够使用
NoOpPasswordEncoder
验证旧的明文密码。

Spring Security 提供

PasswordEncoderFactories.createDelegatingPasswordEncoder()

 方法作为方便的默认方法,但您的应用程序不太可能使用这么多不同的密码编码。
更有可能的是,您的应用程序使用 2 种不同的编码,即传统编码(例如 noop)和现代编码(例如 bcrypt),在这种情况下,您可以使用类似于上述
PasswordEncoder
delegatingPasswordEncoder

这些示例的要点是,在大多数情况下,您不需要

createDelegatingPasswordEncoder

 中设置的默认值。但是,如果您仍然想使用 
createDelegatingPasswordEncoder
 中的编码器(除了 
bcrypt
 之外),您可以使用如下所示的 
PasswordEncoder

@Bean public PasswordEncoder delegatingPasswordEncoder() { Map<String, PasswordEncoder> encoders = new HashMap<>(); // Use this encoder for bcrypt encoders.put("bcrypt", new BCryptPasswordEncoder(BCryptVersion.$2Y, 12)); DelegatingPasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders); PasswordEncoder defaultDelegatingPasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); // If a password ID does not match "bcrypt", use defaultDelegatingPasswordEncoder delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(defaultDelegatingPasswordEncoder); return delegatingPasswordEncoder; }
    
© www.soinside.com 2019 - 2024. All rights reserved.