1. 程式人生 > >spring security原理-學習筆記2-核心元件

spring security原理-學習筆記2-核心元件

核心元件

AuthenticationManager,ProviderManager和AuthenticationProvider

AuthenticationManager只是一個介面,實際中是如何運作的?如果我們需要檢查多個身份驗證資料庫或不同身份驗證服務(如資料庫和LDAP伺服器)的組合,該怎麼辦?

Spring Security中的預設實現為ProviderManager,ProviderManager本身不處理身份驗證請求,它會委託給AuthenticationProvider列表進行處理,每個列表都會被查詢以檢視它是否可以執行認證。每個提供程式將丟擲異​​常或返回完全填充的Authentication物件。

org.springframework.security.authentication.ProviderManager內部實現:

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

UserDetailsS​​ervice實現

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