如何从Spring Security中使用新的PasswordEncoder

从Spring Security 3.1.4.RELEASE开始,旧的org.springframework.security.authentication.encoding.PasswordEncoder 已被弃用 ,转而使用org.springframework.security.crypto.password.PasswordEncoder 。 由于我的应用程序还没有公开发布,我决定转移到新的,不被弃用的API。

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

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

在login过程中,Spring也使用我的bean来validation用户是否可以login。我无法在新密码编码器中实现这一点,因为SHA-1的缺省实现 – StandardPasswordEncoder只能添加一个编码器创build过程中的全局秘密盐。

有没有任何合理的方法来设置它与未弃用的API?

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

因为你根本不用担心盐的问题,所以细节完全封装在编码器中。 使用BCrypt比使用简单的哈希algorithm更强大,也是与使用其他语言的应用程序兼容的标准。

没有理由为新的应用程序select任何其他选项。

这是为我工作的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); 

有关弹簧安全的更多详细示例,请点击这里

希望这会有所帮助。

谢谢

我有一个类似的问题。 我需要保留传统的encryption密码( Base64 / SHA-1 /随机盐编码 ),因为用户不想更改密码或重新注册。 不过我也想用BCrypt编码器。

我的解决scheme是编写一个定制的解码器,检查在匹配之前首先使用哪种encryption方法( BCrypted$开头)。

为了解决盐问题,我通过修改后的用户对象向解码器传递一串盐+encryption密码。

解码器

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


  @PostLoad private void init() { username = emailAddress; //To comply with UserDetails password = salt == null ? password : salt + SPLIT_CHAR + password; } 

您也可以添加一个挂钩,以新的BCrypt格式重新编码密码并将其replace。 从而逐步淘汰旧方法。

刚刚去了网上阅读这个和spring的选项,我第二次卢克的答案,使用BCrypt(它在源代码中提到的spring)。

我发现最好的资源来解释为什么要散列/盐,为什么使用BCrypt是一个不错的select在这里:咸味密码散列 – 做对了 。