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