2013-07-03 61 views
40

從Spring Security 3.1.4.RELEASE開始,舊的org.springframework.security.authentication.encoding.PasswordEncoderhas been deprecated贊成org.springframework.security.crypto.password.PasswordEncoder。由於我的應用尚未發佈給公衆,因此我決定遷移到新的,未棄用的API。如何從Spring Security使用新的PasswordEncoder

到現在爲止,我有一個ReflectionSaltSource可以自動使用用戶的註冊日期爲每個用戶的鹽密碼。

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

在登錄過程中,Spring還用我的豆子適當驗證用戶是否可以或不能登錄,我不能在新的密碼編碼器實現這一點,因爲SHA-1的默認實現 - StandardPasswordEncoder只能在編碼器創建期間添加全局祕密鹽。

有如何與非棄用API將其設置任何合理的方法?

回答

48

如果您還沒有實際註冊任何用戶與您現有的格式,那麼你最好切換到使用BCrypt password encoder代替。

它的麻煩少了很多,因爲你不必擔心鹽在所有 - 細節編碼器內完全封裝。使用BCrypt比使用簡單哈希算法更強大,而且它也是與使用其他語言的應用程序兼容的標準。

實在沒有理由去選擇任何其他選項,新的應用程序。

+3

那麼,如果你真的有註冊用戶呢?我假設Passwordencoder將在某個時候被刪除。如何遷移? – Marc

+7

遷移帳戶通常需要您在用戶成功登錄時重新密碼。您還需要在遷移期間支持多種算法。除此之外,您可能需要重置密碼或最終鎖定或刪除未使用的額外時間的未使用帳戶。這取決於您的系統和要求。我敢肯定,如果你進行一些搜索,你可以找到它的討論,因爲這是一個常見的問題,並隨着密碼db妥協數量的增加變得更相關。至少你沒有使用[純文本](http://ow.ly/qZQh0):-)。 –

+1

我有一個活的應用程序,它使用帶有鹽的舊密碼編碼器。有沒有例子可以說明如何遷移到新的PasswordEncoder? – user2213684

3

剛剛瀏覽互聯網閱讀了這篇文章以及Spring中的選項,我第二次回答Luke的回答,使用了BCrypt(在Spring中的source code中提到過)。

我發現來解釋的最佳資源,爲什麼散列/鹽以及爲什麼使用BCrypt是一個不錯的選擇是在這裏:Salted Password Hashing - Doing it Right

+0

雖然使用bcrypt是一個好主意,但是您鏈接的文章有許多可怕的想法,例如使用快速哈希。有關詳細信息,請參閱reddit註釋http://www.reddit.com/r/programming/comments/1yrnbo/salted_pa​​ssword_hashing_doing_it_right/cfnaqkl –

17

這是BCrypt的實現,它正在爲我工​​作。

在彈簧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); 

對於春季安全Click Here

希望這將有助於更詳細的例子。

謝謝

+0

您的userDetailsS​​erviceImpl中包含什麼? – Richard

5

我有類似的問題。我需要保留傳統的加密密碼(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格式重新編碼的密碼,並更換。因此逐步淘汰舊方法。

相關問題