一、SecurityContext
安全上下文,用戶通過Spring Security 的校驗之后,驗證信息存儲在SecurityContext中
SecurityContext接口只定義了兩個方法,實際上其主要作用就是獲取Authentication對象
二、SecurityContextHolder
SecurityContextHolder看名知義,是一個holder,用來hold住SecurityContext實例的。在典型的web應用程序中,用戶登錄一次,然后由其會話ID標識。服務器緩存持續時間會話的主體信息。在Spring Security中,在請求之間存儲SecurityContext的責任落在SecurityContextPersistenceFilter上,默認情況下,該上下文將上下文存儲為HTTP請求之間的HttpSession屬性。它會為每個請求恢復上下文SecurityContextHolder,並且最重要的是,在請求完成時清除SecurityContextHolder。SecurityContextHolder是一個類,他的功能方法都是靜態的(static)。
SecurityContextHolder可以設置指定JVM策略(SecurityContext的存儲策略),這個策略有三種:
MODE_THREADLOCAL:SecurityContext 存儲在線程中。
MODE_INHERITABLETHREADLOCAL:SecurityContext 存儲在線程中,但子線程可以獲取到父線程中的 SecurityContext。
MODE_GLOBAL:SecurityContext 在所有線程中都相同。
SecurityContextHolder默認使用MODE_THREADLOCAL模式,即存儲在當前線程中。
三、Authentication
authentication 直譯過來是“認證”的意思,在Spring Security 中Authentication用來表示當前用戶是誰,一般來講你可以理解為authentication就是一組用戶名密碼信息。Authentication也是一個接口。
接口有4個get方法,分別獲取
Authorities, 填充的是用戶角色信息。
Credentials,直譯,證書。填充的是密碼。
Details ,用戶信息。
Principal 直譯,形容詞是“主要的,最重要的”,名詞是“負責人,資本,本金”。感覺很別扭,所以,還是不翻譯了,直接用原詞principal來表示這個概念,其填充的是用戶名。
因此可以推斷其實現類有這4個屬性。這幾個方法作用如下:
getAuthorities: 獲取用戶權限,一般情況下獲取到的是用戶的角色信息。
getCredentials: 獲取證明用戶認證的信息,通常情況下獲取到的是密碼等信息。
getDetails: 獲取用戶的額外信息,(這部分信息可以是我們的用戶表中的信息)
getPrincipal: 獲取用戶身份信息,在未認證的情況下獲取到的是用戶名,在已認證的情況下獲取到的是 UserDetails (UserDetails也是一個接口,里邊的方法有getUsername,getPassword等)。
isAuthenticated: 獲取當前 Authentication 是否已認證。
setAuthenticated: 設置當前 Authentication 是否已認證(true or false)。
四、UserDetails
UserDetails,看命知義,是用戶信息的意思。其存儲的就是用戶信息
其接口方法含義如下:
getAuthorites:獲取用戶權限,本質上是用戶的角色信息。
getPassword: 獲取密碼。
getUserName: 獲取用戶名。
isAccountNonExpired: 賬戶是否過期。
isAccountNonLocked: 賬戶是否被鎖定。
isCredentialsNonExpired: 密碼是否過期。
isEnabled: 賬戶是否可用。
五、UserDetailsService
提到了UserDetails就必須得提到UserDetailsService, UserDetailsService也是一個接口,且只有一個方法loadUserByUsername,他可以用來獲取UserDetails。
通常在spring security應用中,我們會自定義一個CustomUserDetailsService來實現UserDetailsService接口,並實現其public UserDetails loadUserByUsername(final String login);方法。我們在實現loadUserByUsername方法的時候,就可以通過查詢數據庫(或者是緩存、或者是其他的存儲形式)來獲取用戶信息,然后組裝成一個UserDetails,(通常是一個org.springframework.security.core.userdetails.User,它繼承自UserDetails) 並返回。
在實現loadUserByUsername方法的時候,如果我們通過查庫沒有查到相關記錄,需要拋出一個異常來告訴spring security來“善后”。這個異常是org.springframework.security.core.userdetails.UsernameNotFoundException。
六、AuthenticationManager
AuthenticationManager 的作用就是校驗Authentication,如果驗證失敗會拋出AuthenticationException異常。AuthenticationException是一個抽象類,因此代碼邏輯並不能實例化一個AuthenticationException異常並拋出,實際上拋出的異常通常是其實現類,如DisabledException,LockedException,BadCredentialsException等。BadCredentialsException可能會比較常見,即密碼錯誤的時候。