什么是SpringSecurity
Spring Security是基于Filter实现的对系统的访问权限进行细粒度的控制,包括用户认证(Authentication)和用户授权(Authorization);认证是验证某个用户是否为系统中的合法主体,授权是验证某个用户是否有权限执行某个操作。众所周知,想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。所以springSecurity在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。
SpringSecurity的启动加载流程
SpringSecurityConfigurer
@EnableWebSecurity ->WebSecurityConfiguration->setFilterChainProxySecurityConfigurer->springSecurityFilterChain->AbstractConfiguredSecurityBuilder.doBuild()。
WebSecurityConfiguration首先调用它setFilterChainProxySecurityConfigurer方法进行webSecurity的初始化;
objectPostProcessor用于构建webSecurity,另外的注解将我们定义的SpringSecurityConfigurer转化到webSecurityConfigurers中。
然后再调用springSecurityFilterChain进行webSecurity的配置
下面的关键开始了
接着调用org.springframework.security.config.annotation.AbstractSecurityBuilder#build方法,进入doBuild()方法
这时候的configurers是”class com.yrd.bpm.security.SpringSecurityConfigurer$$EnhancerBySpringCGLIB$$463f5179” -> “ size = 1”,
doBuild()方法有2个非常重要的方法:init()和performBuild()
首先是init(),只会进入第一个的for循环,调用
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
的init()方法,我们看一下getHttp()方法
gethttp()方法重要的事情做了2件,第一件是构建接口AuthenticationManager的实现,实际是实例化ProviderManager,第二件是对http初始化,执行if(!disableDefaults)内的代码
我们看到http有1个filter和10个configurers
继续向下执行,会执行configure方法,就是我们自定义SpringSecurityConfigurer类的configure方法
这时候http变成了
然后调用web.addSecurityFilterChainBuilder(http),就是把http放入securityFilterChainBuilders,为下面的performBuild()作准备
关键的就是for循环里面的securityFilterChains.add(securityFilterChainBuilder.build()),这个时候又进入doBuild(),处理上图中的http的11个configure。
在doBuild()中init()和configure(), init()对11个configure处理
其中org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer主要配置是否有securityContext,一般jwt的方式是配置stateless为true
configure()将configure转化为filter,
最后performBuilder(),将filter排序后构建DefaultSecurityFilterChain
org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer
一个请求经过SpringSecurity的处理流程
经过上面的流程之后会生成如下13个过滤链
WebAsyncManagerIntegrationFilter
将Security上下文与Spring Web中用于处理异步请求映射的 WebAsyncManager 进行集成。
SecurityContextPersistenceFilter
在每次请求处理之前将该请求相关的安全上下文信息加载到SecurityContextHolder中,然后在该次请求处理完成之后,将SecurityContextHolder中的信息清除,同时将关于这次请求的信息存储到一个SecurityContextRepository中。这里要注意的是SecurityContextRepository的实现有2个,HttpSessionSecurityContextRepository和NullSecurityContextRepository,当你用token验证时候,不用session管理会话时,即stateless为true,会使用NullSecurityContextRepository,这时候SecurityContextHolder里面存取都是空的。
HeaderWriterFilter
用于将头信息加入响应中
LogoutFilter
用于处理退出登录
执行我定义的过滤链
UsernamePasswordAuthenticationFilter
用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自“/login”的请求。
从表单中获取用户名和密码时,默认使用的表单name值为“username”和“password”,这两个值可以通过设置这个过滤器的usernameParameter 和 passwordParameter 两个参数的值进行修改。
ConcurrentSessionFilter
如果session没过期, 就会更新session里的”last update” date/time;
如果session过期, 就会调用logout handlers(一般是LogoutFilter)去销毁session, 然后跳转到expiredUrl;
RequestCacheAwareFilter
用于用户登录成功后,重新恢复因为登录被打断的请求;
SecurityContextHolderAwareRequestFilter
对request包装的目的主要是实现servlet api的一些接口方法isUserInRole、getRemoteUser
AnonymousAuthenticationFilter
如果没有任何认证程序机制更新SecurityContextHolder,一个匿名的对象将存放到这里
SessionManagementFilter
当用户重启浏览器, 然后使用remember-me授权成功后, 再直接访问授权后的url. 这时, session里没有了”SPRING_SECURITY_CONTEXT”属性. 那么这个请求会被此过滤器拦截. 这时得到的authentication是RemembermeAuthentication的实例。
当session因过期而被容器自动销毁时, 若用户继续发出请求, 这个请求会放在一个新的session里, 新session里没有设置”SPRING_SECURITY_CONTEXT”属性, 那么这个请求也会被这个过滤器拦截. 这时得到的authentication是AnonymousAuthentication的实例。
ExceptionTranslationFilter
此过滤器的作用是处理中FilterSecurityInterceptor抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。
FilterSecurityInterceptor
功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。
功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。
功能三:如果用户已登录,也具有访问当前资源的权限,则放行。
SpringSecurity的使用
参考github:https://github.com/Luckylau/Spring-Learning.git
参考文章
https://blog.csdn.net/liushangzaibeijing/article/details/81220610