Spring security 基本感知
流程
1.接收請求
1、HTTP基本身份驗證請求通過過濾器鏈直到它到達BasicAuthenticationFilter。
2、HTTP摘要式身份驗證請求通過過濾器鏈,直到它到達DigestAuthenticationFilter。
3、登入表單提交請求(登入表單身份驗證請求)通過過濾器鏈直到它到達UsernamePasswordAuthenticationFilter。
4、x509身份驗證請求通過過濾器鏈直到它到達X509AuthenticationFilter等...
2.根據使用者憑據建立AuthenticationToken
相關的AuthenticationFilter收到身份驗證請求,會從收到的請求中提取使用者名稱和密碼(大多數身份驗證機制都需要使用者名稱和密碼)。 之後,它會根據提取的使用者憑據建立一個Authentication物件。 如果提取的憑據是使用者名稱和密碼,則將使用提取/找到的使用者名稱和密碼建立UsernamePasswordAuthenticationToken。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.security.core; import java.io.Serializable; import java.security.Principal; import java.util.Collection; public interface Authentication extends Principal, Serializable { Collection<? extends GrantedAuthority> getAuthorities(); Object getCredentials(); Object getDetails(); Object getPrincipal(); boolean isAuthenticated(); void setAuthenticated(boolean var1) throws IllegalArgumentException; }
3.建立的AuthenticationToken委派給AuthenticationManagager
它將用於呼叫AuthenticationManager的authenticate方法。 AuthenticationManager只是一個介面,實際的實現是ProviderManager。
public interface AuthenticationManager {
// 核心
Authentication authenticate(Authentication authentication)throws AuthenticationException;
}
ProviderManager有一個配置的AuthenticationProvider列表,應該用於驗證使用者請求。 ProviderManager將遍歷每個提供的AuthenticationProvider,並嘗試根據傳遞的Authentication Object對使用者進行身份驗證(例如: - UsernamePasswordAuthenticationToken)
4.嘗試使用AuthenticationProvider列表進行身份驗證
// 自定義驗證器時需要實現
public interface AuthenticationProvider {
// 驗證規則
Authentication authenticate(Authentication var1) throws AuthenticationException;
// 支援的Authentication型別
boolean supports(Class<?> var1);
}
以下是框架附帶的一些現有身份驗證程式:
- CasAuthenticationProvider
- JaasAuthenticationProvider
- DaoAuthenticationProvider
- OpenIDAuthenticationProvider
- RememberMeAuthenticationProvider
- LdapAuthenticationProvider
5. 驗證資料來源:UserDetailsService
public interface UserDetailsService {
// 根據使用者名稱獲取使用者資訊,返回封裝成UserDetail或實現返回
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
6、7. UserDetails 介面和 User 實現?
UserDetailsService將根據使用者名稱檢索UserDetails(實際實現是User)。
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
User實現:org.springframework.security.core.userdetails.User
8.返回Authentication 或者丟擲 AuthenticationException?
如果使用者成功通過身份驗證,則將返回完全填充的Authentication物件。 否則將丟擲AuthenticationException。
如果丟擲任何AuthenticationException,那將由支援身份驗證機制的已配置AuthenticationEntryPoint處理。
9.驗證完成!
AuthenticationManager將獲取的完全填充的Authentication物件返回到相關的Authentication 過濾器。
然後,相關的AuthenticationFilter會將獲取的身份驗證物件儲存在SecurityContext中,以供將來過濾器使用。 (用於授權過濾器)
SecurityContextHolder.getContext().setAuthentication(authentication);
元件
SecurityContextHolder
SecurityContextHolder使用ThreadLocal來儲存這些詳細資訊,這意味著安全上下文始終可用於同一執行執行緒中的方法,即使安全上下文未作為這些方法的引數顯式傳遞
- 配置:
- SecurityContextHolder.MODE_GLOBAL策略:獨立應用程式,全域性共享使用者資訊
- SecurityContextHolder.MODE_INHERITABLETHREADLOCAL:安全執行緒生成的執行緒也採用相同的安全標識
// 從SecurityContextHolder中獲取使用者身份資訊
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
UserDetailsService
資料來源:UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
校驗實現:AuthenticationProvider
GrantedAuthority
Authentication提供的另一個重要方法是getAuthorities()。 此方法提供GrantedAuthority物件的陣列。GrantedAuthority是授予主體的許可權。 這些許可權通常是“角色”,例如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR