spring security原理-學習筆記2-核心元件
核心元件
AuthenticationManager,ProviderManager和AuthenticationProvider
AuthenticationManager只是一個介面,實際中是如何運作的?如果我們需要檢查多個身份驗證資料庫或不同身份驗證服務(如資料庫和LDAP伺服器)的組合,該怎麼辦?
Spring Security中的預設實現為ProviderManager,ProviderManager本身不處理身份驗證請求,它會委託給AuthenticationProvider列表進行處理,每個列表都會被查詢以檢視它是否可以執行認證。每個提供程式將丟擲異常或返回完全填充的Authentication物件。
public Authentication authenticate(Authentication authentication) throws AuthenticationException { 遍歷List<AuthenticationProvider> 列表{ if(provider.supports(toTest)){ result = provider.authenticate(authentication); this.copyDetails(authentication, result); } } this.parent.authenticate(authentication); eventPublisher.publishAuthenticationSuccess(result); }
還記得我們的好朋友UserDetails和UserDetailsService嗎?驗證身份驗證請求的最常用方法是載入相應的UserDetails並檢查載入的密碼與使用者輸入的密碼。這是DaoAuthenticationProvider使用的方法(見下文)。載入的UserDetails物件 - 特別是它包含的GrantedAuthority - 將在構建完全填充的Authentication物件時使用,該物件從成功的身份驗證返回並存儲在SecurityContext中。
DaoAuthenticationProvider繼承org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserDetails user = this.userCache.getUserFromCache(username);
if(user==null){
user = this.retrieveUser(username, (UsernamePasswordAuthenticationToken)authentication);
}
this.preAuthenticationChecks.check(user);
this.additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication);
this.postAuthenticationChecks.check(user);
Object principalToReturn = user.getUsername();
return this.createSuccessAuthentication(principalToReturn, authentication, user);
}
AuthenticationProvider實現類:org.springframework.security.authentication.dao.DaoAuthenticationProvider內部實現
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
} else {
return loadedUser;
}
}
UserDetailsService實現
In-Memory Authentication
<user-service id="userDetailsService">
<!-- Password以{noop}為字首,指示將其委託給passwordencoder應該使用NoOpPasswordEncoder。這是不安全的生產,但使閱讀樣本中更容易。通常密碼應該使用BCrypt雜湊 -->
<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
</user-service>
JdbcDaoImpl
從資料庫載入
密碼編碼
歷史的密碼編碼
- 儲存密碼原始文字
- 儲存通過單向雜湊(如SHA-256)的密碼
- 為了降低Rainbow Tables的有效性,鼓勵開發人員使用salted密碼
- 現在鼓勵開發人員利用自適應單向函式來儲存密碼。開發人員來設定不同的worker factor滿足不同的安全需要,在安全和效率之間做出權衡。例如: bcrypt , PBKDF2 , scrypt , and Argon2 .
DelegatingPasswordEncoder(spring5.0後的新特性)
- 確保使用當前密碼儲存建議對密碼進行編碼
- 允許驗證現代和傳統格式的密碼
- 允許將來升級編碼
將編碼方式存入密碼文字
BCryptPasswordEncoder
https://en.wikipedia.org/wiki/Bcrypt
Pbkdf2PasswordEncoder
https://en.wikipedia.org/wiki/PBKDF2
SCryptPasswordEncoder
https://en.wikipedia.org/wiki/Scr