如何使用Spring Security的新PasswordEncoder

fra*_*acz 55 java spring spring-security

从Spring Security 3.1.4.RELEASE开始,旧的org.springframework.security.authentication.encoding.PasswordEncoder 已经被弃用org.springframework.security.crypto.password.PasswordEncoder.由于我的应用尚未向公众发布,我决定转向新的,而不是弃用的API.

到目前为止,我有一个ReflectionSaltSource自动使用用户的注册日期作为每用户盐密码.

String encodedPassword = passwordEncoder.encodePassword(rawPassword, saltSource.getSalt(user));
Run Code Online (Sandbox Code Playgroud)

在登录过程中,Spring还使用我的bean来验证用户是否可以登录.我无法在新密码编码器中实现这一点,因为SHA-1的默认实现 - StandardPasswordEncoder只能添加全局编码器创建过程中的秘密盐.

有没有合理的方法如何使用未弃用的API进行设置?

Sha*_*eep 56

如果您实际上没有使用现有格式注册任何用户,那么您最好切换到使用BCrypt密码编码器.

它不那么麻烦,因为您根本不必担心盐 - 细节完全封装在编码器中.使用BCrypt比使用普通哈希算法更强大,它也是与使用其他语言的应用程序兼容的标准.

实际上没有理由为新应用程序选择任何其他选项.

  • 迁移帐户通常要求您在用户成功登录时重新哈希密码.您还必须支持迁移期间的多种算法.除此之外,您可能需要重置密码或最终锁定或删除未使用的未使用帐户.这取决于您的系统和要求.如果你进行一些搜索,我相信你可以找到它的讨论,因为它是一个常见的问题,随着密码db的数量增加而变得更加相关.至少你没有使用[明文](http://ow.ly/qZQh0):-). (8认同)
  • 那么,如果您确实拥有注册用户呢?我假设Passwordencoder将在某个时候删除.如何迁移? (5认同)
  • 我有一个现场应用程序,并使用旧的PasswordEncoder与salt.有没有关于如何迁移到新的PasswordEncoder的例子? (2认同)

Rav*_*ant 17

这是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"/>
Run Code Online (Sandbox Code Playgroud)

在java类中

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(yourpassword);
Run Code Online (Sandbox Code Playgroud)

有关弹簧安全性的更详细示例,请单击此处

希望这会有所帮助.

谢谢


Sim*_*ins 5

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

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

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

解码器

@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

用户对象

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;
Run Code Online (Sandbox Code Playgroud)

.
.

    @PostLoad
    private void init() {

    username = emailAddress; //To comply with UserDetails
    password = salt == null ? password : salt + SPLIT_CHAR + password;
    }        
Run Code Online (Sandbox Code Playgroud)

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