Spring Security源码解析之权限访问控制是如何做到的

论坛 期权论坛 脚本     
niminba   2021-5-23 02:38   1900   0

〇、前文回顾

在实战篇《话说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);
 }
 ...
}

这个过滤器的配置器是在 HttpSecurityauthorizeRequests() 方法中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);
 }
 ...
}

这个过滤器的配置器是在 HttpSecurityexceptionHandling() 方法中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表达式 方法源码如下,继续往下走

可以自定义Spel表达式 @rbacService.hasPermission (request, authentication) hasPermission(request, authentication) ,该方法在自定义的RbacServiceImpl类中

四、总结

  • 访问控制的核心过滤器是 FilterSecurityInterceptor ,当然这个是可选的,我们完全也可以自定义一个过滤器去处理权限访问。
  • 处理访问异常处理的过滤器是 ExceptionTranslationFilter ,里面逻辑很简单,给response设置异常信息错误码,再返回给客户端。

以上就是Spring Security源码解析之权限访问控制是如何做到的的详细内容,更多关于Spring Security权限访问控制的资料请关注社区其它相关文章!

转播转播
分享到 :
0 人收藏
返回列表
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP