spring security认证体系
·
spring security


常用的类
FilterChainProxy: 原生的Filter ,,,他会委托给一个指定名字的spring bean执行,这个bean的名字就是springSecurityFilterChain, 他会通过不同的url,将连接转发到不同的SecurityFilterChain上面处理SecurityFilterChain: 就是一系列Filter的集合Authentication: 用户认证的信息AuthenticationManager: 管理怎么去认证,会管理一系列AuthenticationProvider,,遍历的去进行认证AuthenticationProvider: 认证方案的具体实现UserDetailsService: 怎么去加载用户信息,, 常用的是从数据库加载SecurityContextHolder: 认证成功之后存放信息HttpSecurity: 配置这个SecurityFilterChain链条AuthorizeConfigurer: 链条里面有很多filter,,,configurer就是将这些filter归类成configurer,,,比如 httpSecurity配置中formLogin()配置表单登录,就是一个FormLoginConfigurer,比如说处理csrf的也是一个CsrfConfigurer, 它里面会包含相关的filter,,然后将filter放入到 一个filter的集合中,,这个集合在最后build()方法中被构建成一个SecurityFilterChain
代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Request {
private String username;
private String password;
}
public class Response {
}
认证信息对象:
public interface Authentication {
Object getPrincipal();
Object getCredentials();
boolean isAuthenticated();
void setAuthenticated(boolean authenticated);
}
public class UsernamePasswordAuthenticationToken implements Authentication{
private Object principal;
private Object credentials;
private boolean authenticated;
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
this.principal = principal;
this.credentials = credentials;
}
@Override
public Object getPrincipal() {
return principal;
}
@Override
public Object getCredentials() {
return credentials;
}
@Override
public boolean isAuthenticated() {
return authenticated;
}
@Override
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
}
认证管理器:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication);
}
认证管理器的实现类:
public class ProviderManager implements AuthenticationManager{
private List<AuthenticationProvider> providers;
public ProviderManager(List<AuthenticationProvider> providers) {
this.providers = providers;
}
@Override
public Authentication authenticate(Authentication authentication) {
for (AuthenticationProvider provider : providers) {
if (provider.supports(authentication.getClass())) {
Authentication result = provider.authenticate(authentication);
if (result != null && result.isAuthenticated()){
return result;
}
}
}
throw new RuntimeException("认证失败");
}
}
单独的认证管理provider执行者:
public interface AuthenticationProvider {
boolean supports(Class<?> clazz);
Authentication authenticate(Authentication authentication);
}
public class DaoAuthenticationProvider implements AuthenticationProvider{
@Override
public boolean supports(Class<?> clazz) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(clazz);
}
@Override
public Authentication authenticate(Authentication authentication) {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
if (username.equals("admin") && password.equals("123")){
authentication.setAuthenticated(true);
return authentication;
}
throw new RuntimeException("认证失败,用户名错误");
}
}
过滤器:
public interface Filter {
void doFilter(Request request, Response response, SecurityFilterChain chain);
}
过滤器链:会挨个的执行里面的过滤器
public class SecurityFilterChain {
private List<Filter> filters;
private int currentIndex = 0;
public SecurityFilterChain(List<Filter> filters) {
this.filters = filters;
}
public void doFilter(Request request,Response response){
if (currentIndex < filters.size()){
Filter filter = filters.get(currentIndex);
System.out.println("执行filter"+filter.getClass().getSimpleName());
currentIndex+=1;
filter.doFilter(request,response,this);
}else{
System.out.println("finish....");
}
}
}
构建过滤器链的对象:HttpSecurity,,会根据DSL语言,去构建多个SecurityFilterChain对象
public class HttpSecurity {
private List<SecurityConfigurer> configurers = new ArrayList<>();
private List<Filter> filters = new ArrayList<>();
public HttpSecurity formLogin(){
configurers.add(new FormLoginConfigurer());
return this;
}
public HttpSecurity authorize(){
configurers.add(new AuthorizeConfigurer());
return this;
}
public HttpSecurity addFilter(Filter filter){
filters.add(filter);
return this;
}
/**
* 构建HttpSecurityChain
* @return
*/
public SecurityFilterChain build(){
//
for (SecurityConfigurer configurer : configurers) {
configurer.init(this);
}
for (SecurityConfigurer configurer : configurers) {
configurer.configure(this);
}
return new SecurityFilterChain(filters);
}
}
configurer配置模块:将一种模块内的filter打包进去:
public interface SecurityConfigurer {
/**
*
* @param http 核心的builder
*/
void init(HttpSecurity http);
void configure(HttpSecurity http);
}
public class FormLoginConfigurer implements SecurityConfigurer{
@Override
public void init(HttpSecurity http) {
System.out.println("初始化 formlogin configurer");
}
@Override
public void configure(HttpSecurity http) {
http.addFilter(new FormLoginFilter());
}
}
public class AuthorizeConfigurer implements SecurityConfigurer{
@Override
public void init(HttpSecurity http) {
System.out.println("authorize configurer init");
}
@Override
public void configure(HttpSecurity http) {
http.addFilter(new AuthorizationFilter());
}
}
每一种configurer都会配置各自的Filter:
比如 FormLoginConfigurer,我就配置了一个FormLoginFilter
public class FormLoginFilter implements Filter{
@Override
public void doFilter(Request request, Response response, SecurityFilterChain chain) {
System.out.println("form login filter");
chain.doFilter(request,response);
}
}
public class AuthorizationFilter implements Filter{
@Override
public void doFilter(Request request, Response response, SecurityFilterChain chain) {
System.out.println("authorization filter");
chain.doFilter(request,response);
}
}
管理上下文认证信息的threadlocal:
public class SecurityContextHolder {
private static ThreadLocal<Authentication> CONTEXT_HOLDER = new ThreadLocal<>();
public static Authentication get(){
return CONTEXT_HOLDER.get();
}
public static void set(Authentication authentication){
CONTEXT_HOLDER.set(authentication);
}
public static void clear(){
CONTEXT_HOLDER.remove();
}
}
自定义校验登录的filter:
public class UsernamePasswordAuthenticationFilter implements Filter{
private AuthenticationManager authenticationManager;
public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public void doFilter(Request request, Response response, SecurityFilterChain chain) {
String username = request.getUsername();
String password = request.getPassword();
System.out.println("执行登录认证");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
try {
Authentication auth = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
SecurityContextHolder.set(auth);
System.out.println("登录成功");
chain.doFilter(request,response);
} catch (Exception e) {
System.out.println("登录失败");
throw new RuntimeException(e);
}
}
}
测试:
public static void main(String[] args) {
HttpSecurity httpSecurity = new HttpSecurity();
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
ProviderManager manager = new ProviderManager(Arrays.asList(daoAuthenticationProvider));
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(manager);
// todo spring security中 Filter排序
SecurityFilterChain securityFilterChain = httpSecurity.formLogin().authorize()
.addFilter(filter)
.build();
Request request = new Request("admin","123");
Response response = new Response();
securityFilterChain.doFilter(request,response);
}
}
这个spring security的认证流程demo,用到的设计模式:
- 责任链
- 门面模式+调度中心 : AuthenticationManager去做认证的时候,根据判断support()是否支持这种认证进行调度
- 策略模式
- 构建者模式
- 策略+模块化 : configurer体系,,FormLoginConfigurer,,,OAuth2LoginConfigurer
公众号:代码源记
更多推荐


所有评论(0)