SpringSecurity 默认表单登录页展示流程源码
本篇主要讲解 SpringSecurity提供的默认表单登录页 它是如何展示的的流程,
涉及
1.FilterSecurityInterceptor,
2.ExceptionTranslationFilc,xmccmc,ter ,
3.DefaultLoginPageGeneratingFilter 过滤器,
并且简单介绍了 AccessDecisionManager 投票机制
1.准备工作(体验SpringSecurity默认表单认证)
1.1 创建SpringSecurity项目
先通过IDEA 创建一个SpringBoot项目 并且依赖SpringSecurity,Web依赖
此时pom.xml会自动添加
org.springframework.boot
spring-boot-starter-security
1.2 提供一个接口
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "Hello SpringSecurity";
}
}
,
1.3 启动项目
直接访问 提供的接口
会发现浏览器被直接重定向到了 /login 并且显示如下默认的表单登录页
1.4 登录
在启动项目的时候 控制台会打印一个 seuciryt password : xxx
Using generated security password: f520875f-ea2b-4b5d-9b0c-f30c0c17b90b
直接登录
用户名:user 密码 :f520875f-ea2b-4b5d-9b0c-f30c0c17b90b
登录成功并且 浏览器又会重定向到 刚刚访问的接口
2.springSecurityFilterchain 过滤器链
如果你看过我另一篇关于SpringSecurity初始化源码的博客,那么你一定知道当SpringSecurity项目启动完成后会初始化一个 springSecurityFilterchain 它内部 additionalFilters属性初始化了很多Filter 如下
所有的请求都会经过这一系列的过滤器 Spring Security就是通过这些过滤器 来进行认证授权等
3.FilterSecurityInterceptor (它会判断这次请求能否通过)
FilterSecurityInterceptor是过滤器链中最后一个过滤器,主要用于判断请求能否通过,内部通过AccessDecisionManager 进行投票判断
当我们未登录访问
请求会被 FilterSecurityInterceptor 拦截
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
重点看invoke方法
public void invoke(FilterInvocation fi) throws IOException, ServletException {
if ((fi.getRequest() != null)
&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
&& observeOncePerRequest) {
// filter already applied to this request and user wants us to observe
// once-per-request handling, so don't re-do security checking
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
else {
// first time this request being called, so perform security checking
if (fi.getRequest() != null && observeOncePerRequest) {
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, null);
}
}
源码中有这样一句,其实就是判断当前用户是否能够访问指定的接口,可以则执行 fi.getChain().doFilter 调用访问的接口
否则 内部会抛出异常
InterceptorStatusToken token = super.beforeInvocation(fi);
beforeInvocation 方法内部是通过 accessDecisionManager 去做决定的
Spring Security已经内置了几个基于投票的