〇、前文回顾
在实战篇《话说Spring Security权限管理(源码详解)》我们学习了Spring Security强大的访问控制能力,只需要进行寥寥几行的配置就能做到权限的控制,本篇来看看它到底是如何做到的。
一、再聊过滤器链
源码篇中反复提到,请求进来需要经过的是一堆过滤器形成的过滤器链,走完过滤器链未抛出异常则可以继续访问后台接口资源,而最后一个过滤器就是来判断请求是否有权限继续访问后台资源,如果没有则会将拒绝访问的异常往上向异常过滤器抛,异常过滤器会对异常进行翻译,然后响应给客户端。
所以,一般情况下最后一个过滤器是做权限访问控制的核心过滤器FilterSecurityInterceptor ,而倒数第二个是异常翻译过滤器ExceptionTranslationFilter ,将异常进行翻译然后响应给客户端。比如我们实战项目过滤器链图解
二、过滤器的创建
FilterSecurityInterceptor的创建
这个过滤器的配置器是 ExpressionUrlAuthorizationConfigurer ,它的父类 AbstractInterceptUrlConfigurer 中的 configure() 方法创建了这个过滤器。
abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<C, H> {
...
@Override
public void configure(H http) throws Exception {
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
if (metadataSource == null) {
return;
}
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
http, metadataSource, http.getSharedObject(AuthenticationManager.class));
if (filterSecurityInterceptorOncePerRequest != null) {
securityInterceptor
.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
}
securityInterceptor = postProcess(securityInterceptor);
http.addFilter(securityInterceptor);
http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
}
...
}
这个过滤器的配置器是在 HttpSecurity 的 authorizeRequests() 方法中apply进来的,在我们自己配置的核心配置器中使用的就是该种基于 HttpServletRequest 限制访问的方式。
ExceptionTranslationFilter的创建
这个过滤器的配置器是 ExceptionHandlingConfigurer ,它自己的 configure() 方法中创建了这个过滤器。
public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<ExceptionHandlingConfigurer<H>, H> {
...
@Override
public void configure(H http) throws Exception {
AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
entryPoint, getRequestCache(http));
if (accessDeniedHandler != null) {
exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);
}
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
http.addFilter(exceptionTranslationFilter);
}
...
}
这个过滤器的配置器是在 HttpSecurity 的 exceptionHandling() 方法中apply进来的,和上面不同的是,这个过滤器配置器会默认被apply进 HttpSecurity ,在 WebSecurityConfigurerAdapter 中的 init() 方法,里面调用了 getHttp() 方法,这里定义了很多默认的过滤器配置,其中就包括当前过滤器配置。
三、源码流程
FilterSecurityInterceptor
- 进入:
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- 进入:
invoke(FilterInvocation fi)
- 进入:
beforeInvocation(Object object)
这个方法里面有个 attributes ,里面获取的就是当前request请求所能匹配中的权限Spel表达式,比如这里是 hasRole('ROLE_BUYER')
方法源码如下,继续往下走
| 可以自定义Spel表达式 |
@rbacService.hasPermission (request, authentication) |
hasPermission(request, authentication) ,该方法在自定义的RbacServiceImpl类中 |