我有類似的問題。我需要保留傳統的加密密碼(Base64/SHA-1 /隨機鹽編碼),因爲用戶不想更改密碼或重新註冊。不過我想用BCrypt編碼器也向前移動。
我的解決方案是編寫一個定製解碼器,檢查在匹配之前首先使用哪種加密方法(BCrypted ones開始於$
)。
爲了解決鹽問題,我通過我的修改過的用戶對象傳遞給解碼器級聯的字符串 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;
。
。
@PostLoad
private void init() {
username = emailAddress; //To comply with UserDetails
password = salt == null ? password : salt + SPLIT_CHAR + password;
}
您還可以添加一個鉤子在新BCrypt格式重新編碼的密碼,並更換。因此逐步淘汰舊方法。
那麼,如果你真的有註冊用戶呢?我假設Passwordencoder將在某個時候被刪除。如何遷移? – Marc
遷移帳戶通常需要您在用戶成功登錄時重新密碼。您還需要在遷移期間支持多種算法。除此之外,您可能需要重置密碼或最終鎖定或刪除未使用的額外時間的未使用帳戶。這取決於您的系統和要求。我敢肯定,如果你進行一些搜索,你可以找到它的討論,因爲這是一個常見的問題,並隨着密碼db妥協數量的增加變得更相關。至少你沒有使用[純文本](http://ow.ly/qZQh0):-)。 –
我有一個活的應用程序,它使用帶有鹽的舊密碼編碼器。有沒有例子可以說明如何遷移到新的PasswordEncoder? – user2213684