Java 如何使用Spring Security提供的新密码编码器

Java 如何使用Spring Security提供的新密码编码器,java,spring,spring-security,Java,Spring,Spring Security,从SpringSecurity 3.1.4.RELEASE开始,旧的org.springframework.Security.authentication.encoding.PasswordEncoder支持org.springframework.Security.crypto.password.PasswordEncoder。由于我的应用程序尚未向公众发布,我决定使用新的、未被弃用的API 到目前为止,我有一个ReflectionSaltSource,它根据用户salt自动使用用户的注册日期作

从SpringSecurity 3.1.4.RELEASE开始,旧的
org.springframework.Security.authentication.encoding.PasswordEncoder
支持
org.springframework.Security.crypto.password.PasswordEncoder
。由于我的应用程序尚未向公众发布,我决定使用新的、未被弃用的API

到目前为止,我有一个
ReflectionSaltSource
,它根据用户salt自动使用用户的注册日期作为密码

String encodedPassword = passwordEncoder.encodePassword(rawPassword, saltSource.getSalt(user));
在登录过程中,Spring还使用MyBeans来适当验证用户是否可以登录。我无法在新的密码编码器中实现这一点,因为SHA-1-
StandardPasswordEncoder
的默认实现只能在编码器创建期间添加全局密码


有没有什么合理的方法可以使用未弃用的API进行设置?

如果您还没有使用现有格式注册任何用户,那么您最好改用

它的麻烦少了很多,因为你根本不必担心盐-细节完全封装在编码器中。使用BCrypt比使用普通哈希算法更强大,而且它也是一个标准,可以与使用其他语言的应用程序兼容


对于一个新的应用程序,真的没有理由选择任何其他选项。

刚刚在互联网上阅读了这篇文章和春季的选项,我支持Luke的答案,使用BCrypt(在春季的文章中提到过)


我找到的解释为什么散列/salt以及为什么使用BCrypt是一个很好的选择的最佳资源是:。

这里是BCrypt的实现,它对我有用

在spring-security.xml中

<authentication-manager >
    <authentication-provider ref="authProvider"></authentication-provider>  
    </authentication-manager>
<beans:bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  <beans:property name="userDetailsService" ref="userDetailsServiceImpl" />
  <beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
<!-- For hashing and salting user passwords -->
    <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
有关spring安全性的更详细示例

希望这会有所帮助


谢谢

我也有类似的问题。我需要保留传统的加密密码(Base64/SHA-1/Random salt Encoded),因为用户不想更改密码或重新注册。然而,我也希望使用BCrypt编码器

我的解决方案是编写一个定制的解码器,在匹配之前先检查使用了哪种加密方法(b加密方法以
$
开头)

为了绕过salt问题,我通过修改后的用户对象将salt+加密密码的串联字符串传递给解码器

解码器

@Component
public class LegacyEncoder implements PasswordEncoder {

    private static final String BCRYP_TYPE = "$";
    private static final PasswordEncoder BCRYPT = new BCryptPasswordEncoder();

    @Override
    public String encode(CharSequence rawPassword) {

    return BCRYPT.encode(rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {

    if (encodedPassword.startsWith(BCRYP_TYPE)) {
        return BCRYPT.matches(rawPassword, encodedPassword);
    }

    return sha1SaltMatch(rawPassword, encodedPassword);
    }

    @SneakyThrows
    private boolean sha1SaltMatch(CharSequence rawPassword, String encodedPassword) {

    String[] saltHash = encodedPassword.split(User.SPLIT_CHAR);

    // Legacy code from old system   
    byte[] b64salt = Base64.getDecoder().decode(saltHash[0].getBytes());
    byte[] validHash = Base64.getDecoder().decode(saltHash[1]);
    byte[] checkHash = Utility.getHash(5, rawPassword.toString(), b64salt);

    return Arrays.equals(checkHash, validHash);
    }

}
用户对象

public class User implements UserDetails {

    public static final String SPLIT_CHAR = ":";

    @Id
    @Column(name = "user_id", nullable = false)
    private Integer userId;

    @Column(nullable = false, length = 60)
    private String password;

    @Column(nullable = true, length = 32)
    private String salt;
.
.


您还可以添加一个钩子,以新的BCrypt格式重新编码密码并替换它。因此,逐步淘汰旧方法。

那么,如果您确实有注册用户呢?我假设Passwordencoder将在某个时候被删除。如何迁移?迁移帐户通常需要在用户成功登录时重新散列密码。您还必须在迁移期间支持多种算法。除此之外,您可能需要重新设置密码,或者最终锁定或删除在一段时间内未使用的未使用帐户。这取决于您的系统和要求。我相信,如果您进行一些搜索,您可以找到关于它的讨论,因为这是一个常见的问题,并且随着密码数据库泄露数量的增加,它变得更加相关。至少你没有使用:-)。我有一个应用程序是活的,并且正在使用旧的密码编码器和salt。有没有关于如何迁移到新的PasswordEncoder的示例?代码方面它并不太复杂-请参阅示例。它更多地是关于所涉及的过程,基于您的用户登录的频率和您希望迁移过程花费的时间等因素,可能需要用户在一段时间不活动后更改密码或锁定帐户,诸如此类。您的userDetailsServiceImpl中包含了什么?虽然使用bcrypt是一个好主意,你链接到的文章有很多可怕的想法,比如使用快速哈希。有关详细信息,请参阅reddit注释
public class User implements UserDetails {

    public static final String SPLIT_CHAR = ":";

    @Id
    @Column(name = "user_id", nullable = false)
    private Integer userId;

    @Column(nullable = false, length = 60)
    private String password;

    @Column(nullable = true, length = 32)
    private String salt;
    @PostLoad
    private void init() {

    username = emailAddress; //To comply with UserDetails
    password = salt == null ? password : salt + SPLIT_CHAR + password;
    }