首页 文章

如何使用Spring Security的新PasswordEncoder

提问于
浏览
47

截至Spring Security 3.1.4.RELEASE,旧 org.springframework.security.authentication.encoding.PasswordEncoder has been deprecated赞成 org.springframework.security.crypto.password.PasswordEncoder . 由于我的应用尚未向公众发布,我决定转向新的,而不是弃用的API .

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

String encodedPassword = passwordEncoder.encodePassword(rawPassword, saltSource.getSalt(user));

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

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

4 回答

  • 50

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

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

    对于新应用程序,没有理由选择任何其他选项 .

  • 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"/>
    

    在java类中

    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    String hashedPassword = passwordEncoder.encode(yourpassword);
    

    有关 spring 安全的更详细示例Click Here

    希望这会有所帮助 .

    谢谢

  • 3

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

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

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

    Decoder

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

    User Object

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

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

  • 5

    刚刚在互联网上阅读了这篇以及Spring I _1046811的答案,请使用BCrypt(它在Spring的source code中提到) .

    我发现解释为什么哈希/盐以及为什么使用BCrypt的最佳资源是一个很好的选择:Salted Password Hashing - Doing it Right .

相关问题