Spring Security的基本原理
Spring Security的本質就是一個過濾器鍊,擁有很多過濾器
一、檢視源碼
FilterSecurityInterceptor過濾器
是一個方法級的過濾器,基本位于過濾器的最底部
可以在idea中按下兩次shift鍵進行查找,如下圖
源碼
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.security.web.access.intercept;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
private FilterInvocationSecurityMetadataSource securityMetadataSource;
private boolean observeOncePerRequest = true;
public FilterSecurityInterceptor() {
}
public void init(FilterConfig arg0) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
this.invoke(fi);
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
this.securityMetadataSource = newSource;
}
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
if (fi.getRequest() != null && fi.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null && this.observeOncePerRequest) {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} else {
if (fi.getRequest() != null && this.observeOncePerRequest) {
fi.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
}
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, (Object)null);
}
}
public boolean isObserveOncePerRequest() {
return this.observeOncePerRequest;
}
public void setObserveOncePerRequest(boolean observeOncePerRequest) {
this.observeOncePerRequest = observeOncePerRequest;
}
}
super.beforeInvocation(fi) 表示檢視之前的 filter 是否通過。
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());表示真正的調用背景的服務。
ExceptionTranslationFilter過濾器
是異常過濾器,用來處理在認證授權過程中抛出的異常
源碼略~
UsernamePasswordAuthenticationFilter
對/login 的 POST 請求做攔截,校驗表單中使用者名,密碼
源碼略~
二、過濾器的加載過程
三、兩個重要的接口
UserDetailsService 接口
當沒有對項目進行任何設定的時候,賬号和密碼是由 Spring Security 定義生成的。而在實際項目中賬号和密碼都是從資料庫中查詢出來的。 是以我們要通過自定義邏輯控制認證邏輯
而當需要自定義控制邏輯時也就是說當我們需要查詢資料庫時,實作UserDetailsService 接口即可
- 建立類繼承UsernamePasswordAuthenticationFilter,重寫三個方法
- 建立類實作UserDetailService,編寫查詢資料過程,傳回User對象,這個User對象是安全架構提供對象
PasswordEncoder 接口
通過實作該接口,實作對傳回的User密碼進行加密
執行個體
@Test
public void test01(){
// 建立密碼解析器
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// 對密碼進行加密
String atguigu = bCryptPasswordEncoder.encode("atguigu");
// 列印加密之後的資料
System.out.println("加密之後資料:\t"+atguigu);
//判斷原字元加密後和加密之前是否比對
boolean result = bCryptPasswordEncoder.matches("atguigu", atguigu);
// 列印比較結果
System.out.println("比較結果:\t"+result);
}