1. SpringSecurity核心源码分析
分析SpringSecurity的核心原理,那么我们从哪开始分析?以及我们要分析哪些内容?
- 系统启动的时候SpringSecurity做了哪些事情?
- 第一次请求执行的流程是什么?
- SpringSecurity中的认证流程是怎么样的?
1.1 系统启动
当我们的Web服务启动的时候,SpringSecurity做了哪些事情?当系统启动的时候,肯定会加载我们配置的web.xml文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app version="2.5" id="WebApp_ID" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Archetype Created Web Application</display-name>
<!-- 初始化spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- post乱码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 前端控制器 -->
<servlet>
<servlet-name>dispatcherServletb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServletb</servlet-name>
<!-- 拦截所有请求jsp除外 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置过滤器链 springSecurityFilterChain 名称固定 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
web.xml中配置的信息:
- Spring的初始化(会加载解析SpringSecurity的配置文件)
- SpringMVC的前端控制器初始化
- 加载DelegatingFilterProxy过滤器
Spring的初始化操作和SpringSecurity有关系的操作是,会加载介绍SpringSecurity的配置文件,将相关的数据添加到Spring容器中
SpringMVC的初始化和SpringSecurity其实是没有多大关系的
DelegatingFilterProxy过滤器:拦截所有的请求。而且这个过滤器本身是和SpringSecurity没有关系的!!!在之前介绍Shiro的时候,和Spring整合的时候我们也是使用的这个过滤器。 其实就是完成从IoC容器中获取DelegatingFilterProxy这个过滤器配置的 FileterName 的对象。
系统启动的时候会执行DelegatingFilterProxy的init方法
protected void initFilterBean() throws ServletException {
synchronized(this.delegateMonitor) {
// 如果委托对象为null 进入
if (this.delegate == null) {
// 如果targetBeanName==null
if (this.targetBeanName == null) {
// targetBeanName = 'springSecurityFilterChain'
this.targetBeanName = this.getFilterName();
}
// 获取Spring的容器对象
WebApplicationContext wac = this.findWebApplicationContext();
if (wac != null) {
// 初始化代理对象
this.delegate = this.initDelegate(wac);
}
}
}
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
// springSecurityFilterChain
String targetBeanName = this.getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
// 从IoC容器中获取 springSecurityFilterChain的类型为Filter的对象
Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);
if (this.isTargetFilterLifecycle()) {
delegate.init(this.getFilterConfig());
}
return delegate;
}
init方法的作用是:从IoC容器中获取 FilterChainProxy的实例对象,并赋值给 DelegatingFilterProxy的delegate属性
1.2 第一次请求
客户发送请求会经过很多歌Web Filter拦截。
然后经过系统启动的分析,我们知道有一个我们定义的过滤器会拦截客户端的所有的请求。DelegatingFilterProxy
当用户请求进来的时候会被doFilter方法拦截
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
// 如果 delegateToUse 为空 那么完成init中的初始化操作
synchronized(this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = this.findWebApplicationContext();