Java中AuthorizationFilter过滤器的功能

 更新时间:2026年02月10日 10:21:00   作者:MrSYJ  
本文主要介绍了Java中AuthorizationFilter过滤器的功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

AuthorizationFilter过滤器的作用

在 Spring Security 框架中,AuthorizationFilter 是负责执行授权(Authorization) 决策的核心过滤器。根据当前的 Authentication(认证信息)和请求上下文,判断当前用户是否有权限访问目标资源。

先看段源码

public class AuthorizationFilter extends GenericFilterBean {

   ...
   private final AuthorizationManager<HttpServletRequest> authorizationManager;

   

   /**
    * Creates an instance.
    * @param authorizationManager the {@link AuthorizationManager} to use
    */
   public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) {
      Assert.notNull(authorizationManager, "authorizationManager cannot be null");
      this.authorizationManager = authorizationManager;
   }

   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
         throws ServletException, IOException {

      HttpServletRequest request = (HttpServletRequest) servletRequest;
      HttpServletResponse response = (HttpServletResponse) servletResponse;

      if (this.observeOncePerRequest && isApplied(request)) {
         chain.doFilter(request, response);
         return;
      }

      if (skipDispatch(request)) {
         chain.doFilter(request, response);
         return;
      }

      String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
      request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
      try {
         //授权决策
         AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
         this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
         if (decision != null && !decision.isGranted()) {
            throw new AccessDeniedException("Access Denied");
         }
         chain.doFilter(request, response);
      }
      finally {
         request.removeAttribute(alreadyFilteredAttributeName);
      }
   }

从上面的代码中可以看出:AuthorizationFilter 本身不直接做授权判断,而是委托给一个 AuthorizationManager 接口.

AuthorizationManager

从上面的代码中可以看出,授权的核心在于调用authorizationManager的check方法,去决定当前的authentication是否有权限访问request

//授权决策
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
@FunctionalInterface
public interface AuthorizationManager<T> {

   /**
    * Determines if access should be granted for a specific authentication and object.
    * @param authentication the {@link Supplier} of the {@link Authentication} to check
    * @param object the {@link T} object to check
    * @throws AccessDeniedException if access is not granted
    */
   default void verify(Supplier<Authentication> authentication, T object) {
      AuthorizationDecision decision = check(authentication, object);
      if (decision != null && !decision.isGranted()) {
         throw new AccessDeniedException("Access Denied");
      }
   }

   /**
    * Determines if access is granted for a specific authentication and object.
    * @param authentication the {@link Supplier} of the {@link Authentication} to check
    * @param object the {@link T} object to check
    * @return an {@link AuthorizationDecision} or null if no decision could be made
    */
   @Nullable
   AuthorizationDecision check(Supplier<Authentication> authentication, T object);

}

AuthorizationManager接口定义了check方法,为什么说叫授权决策,因为check方法返回的是AuthorizationDecision,这是一种授权结果 里面有个字段granted,用来决定是否有权限继续访问当前资源。

    public class AuthorizationDecision implements AuthorizationResult {

   private final boolean granted;

   public AuthorizationDecision(boolean granted) {
      this.granted = granted;
   }

   @Override
   public boolean isGranted() {
      return this.granted;
   }

   @Override
   public String toString() {
      return getClass().getSimpleName() + " [granted=" + this.granted + "]";
   }

}
    

RequestMatcherDelegatingAuthorizationManager

如果你去调试你会发现AuthorizationFilter委托的AuthorizationManager的实现类是 RequestMatcherDelegatingAuthorizationManager,至于为什么是这个实现类,我们后续会出一个文章专门来讲解,大体还是HttpSecurity,因为它就是用来配置过滤器链的,底层就是配置过滤器的。这里不会多讲。拆解一下这个类的名字

  • RequestMatcher:请求匹配器,用于匹配不同的 HTTP 请求(如 /admin/**, /public/**)
  • Delegating:代表“委派”,即它自己不做判断,而是把任务委派给其他具体的 AuthorizationManager
  • AuthorizationManager:授权管理接口,负责做出“允许”或“拒绝”的决策

RequestMatcherDelegatingAuthorizationManager 内部维护了一个列表mappings:

public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {

   private static final AuthorizationDecision DENY = new AuthorizationDecision(false);

   private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
/**
 * A rich object for associating a {@link RequestMatcher} to another object.
 * 从注释中可以看出RequestMatcherEntry就是用来将RequestMatcher和其他对象建立关联的
 * @author Marcus Da Coregio
 * @since 5.5.5
 */
public class RequestMatcherEntry<T> {

   private final RequestMatcher requestMatcher;

   private final T entry;

   public RequestMatcherEntry(RequestMatcher requestMatcher, T entry) {
      this.requestMatcher = requestMatcher;
      this.entry = entry;
   }

   public RequestMatcher getRequestMatcher() {
      return this.requestMatcher;
   }

   public T getEntry() {
      return this.entry;
   }

}

mappings中的每个条目RequestMatcherEntry代表着一种映射关系,里面包含了

  • 一个 RequestMatcher(比如 AntPathRequestMatcher("/admin/**", "GET"))
  • 一个对应的 AuthorizationManager(比如负责判断 hasRole('ADMIN') 的管理器)

接下来我们看下RequestMatcherDelegatingAuthorizationManager的check流程

/**
 * Delegates to a specific {@link AuthorizationManager} based on a
 * {@link RequestMatcher} evaluation.
 * @param authentication the {@link Supplier} of the {@link Authentication} to check
 * @param request the {@link HttpServletRequest} to check
 * @return an {@link AuthorizationDecision}. If there is no {@link RequestMatcher}
 * matching the request, or the {@link AuthorizationManager} could not decide, then
 * null is returned
 */
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
   if (this.logger.isTraceEnabled()) {
      this.logger.trace(LogMessage.format("Authorizing %s", requestLine(request)));
   }
   for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {

      RequestMatcher matcher = mapping.getRequestMatcher();
      MatchResult matchResult = matcher.matcher(request);
      if (matchResult.isMatch()) {
         AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
         if (this.logger.isTraceEnabled()) {
            this.logger.trace(
                  LogMessage.format("Checking authorization on %s using %s", requestLine(request), manager));
         }
         return manager.check(authentication,
               new RequestAuthorizationContext(request, matchResult.getVariables()));
      }
   }
   if (this.logger.isTraceEnabled()) {
      this.logger.trace(LogMessage.of(() -> "Denying request since did not find matching RequestMatcher"));
   }
   return DENY;
}

从上面的代码我们可以看出check的核心流程是:当请求到来时,它会:

  • 遍历这个列表,取出里面的每个RequestMatcher,然后去判断当前RequestMatcher是否和当前请求request匹配,找到匹配后,找到和RequestMatcher匹配的AuthorizationManager
  • 将授权任务委托给该条目对应的 AuthorizationManager
  • 如果没有任何匹配,默认拒绝(或使用默认策略)。

mappings列表中注册的RequestMatcher和AuthorizationManager关系是如何绑定的

后续我会专门出一期文章从源码角度讲解RequestMatcherDelegatingAuthorizationManager是如何完成创建以及初始化mappings的,这里我们会如何使用就好啦。我们经常在配置过滤器链的时候有如下配置

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
        throws Exception {
    System.out.println("filterChain http: " + System.identityHashCode(http));
    http
            .authorizeHttpRequests((authorize) -> authorize
                    .requestMatchers("/admin/**").hasRole("ADMIN")
                    .anyRequest().authenticated()
            );
           

    return http.build();
}

比如这句代码.requestMatchers("/admin/**").hasRole("ADMIN")就是在配置mappings映射关系,也就是当访问/admin/**时,底层会创建一个AuthorityAuthorizationManager来处理授权决策(这块后面出一篇文章细讲),.hasRole("ADMIN")底层会创建一个AuthorizationManager来处理授权请求。

授权结果

从 AuthorizationFilter的源码中我们知道,如果授权没通过的话就会抛出一个AccessDeniedException异常,这个异常通常会被ExceptionTranslationFilter过滤器捕获 然后进行处理,这个我们后续再将

    if (decision != null && !decision.isGranted()) { throw new AccessDeniedException("Access Denied"); }

总结

AuthorizationFilter过滤器是用来实现授权决策的,但是它会委托给 RequestMatcherDelegatingAuthorizationManager来实现具体的授权决策,结合当前请求和authentication来决定是否有权限。但是这里我也留下了几处坑,没有填,后续我会写文章继续填坑

  1. AuthorizationFilter里面的RequestMatcherDelegatingAuthorizationManager是什么时候配置的
  2. RequestMatcherDelegatingAuthorizationManager需要维护一个mappings,用来映射requestMatcher和authorizationManager
  3. 用户配置调用的requestMatchers("/admin/**").hasRole("ADMIN") 等配置,最后怎么生效的,底层原理是什么 4.授权没通过抛出的异常被 ExceptionTranslationFilter捕获后如何自定义处理。

到此这篇关于Java中AuthorizationFilter过滤器的功能的文章就介绍到这了,更多相关Java AuthorizationFilter过滤器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot如何连接两个数据库(多个)

    springboot如何连接两个数据库(多个)

    这篇文章主要介绍了springboot如何连接两个数据库(多个),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java基于递归和循环两种方式实现未知维度集合的笛卡尔积算法示例

    Java基于递归和循环两种方式实现未知维度集合的笛卡尔积算法示例

    这篇文章主要介绍了Java基于递归和循环两种方式实现未知维度集合的笛卡尔积算法,结合实例形式分析了Java使用递归与循环两种方式实现未知维度集合的笛卡尔积相关概念、原理与操作技巧,需要的朋友可以参考下
    2017-12-12
  • Sentinel 断路器在Spring Cloud使用详解

    Sentinel 断路器在Spring Cloud使用详解

    Sentinel是阿里巴巴开源的一款微服务流量控制组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性,本文介绍Sentinel 断路器在Spring Cloud使用,感兴趣的朋友一起看看吧
    2025-02-02
  • Java实现简单的万年历

    Java实现简单的万年历

    这篇文章主要为大家详细介绍了Java实现简单的万年历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • Java Lambda和Stream开发中20个高频错误案例分析与避坑指南

    Java Lambda和Stream开发中20个高频错误案例分析与避坑指南

    本篇文章将聚焦开发中最常见、最高频的20个问题(含语法、函数式接口、Stream流、方法引用、并行流5大模块),每个问题都配套问题描述+错误案例+原因分析+正确解法,希望对大家有所帮助
    2026-04-04
  • Java内存模型详解

    Java内存模型详解

    JMM全称Java Memory Model, 中文翻译Java内存模型,一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,本详细介绍了Java内存模型,感兴趣的同学可以参考一下
    2023-04-04
  • Java9中接口的私有方法详解

    Java9中接口的私有方法详解

    印象中Java 接口就没有论述私有方法这回事。既然 Java 9 添加了这项特性,那么,应该就有它的用途,我们一起来看看 Java 9 中的接口的私有方法是什么样的吧
    2023-04-04
  • Java深入分析讲解反射机制

    Java深入分析讲解反射机制

    反射是框架的灵魂,Java框架底层都是用反射机制+xml配置等来实现的,本文将通过示例详细讲解Java中的反射机制,感兴趣的小伙伴可以跟随小编学习一下
    2022-06-06
  • 实战分布式医疗挂号系统之整合Swagger2到通用模块

    实战分布式医疗挂号系统之整合Swagger2到通用模块

    这篇文章主要为大家介绍了实战分布式医疗挂号系统之整合Swagger2到通用模块,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • 使用SpringBoot集成Redis实现CRUD功能

    使用SpringBoot集成Redis实现CRUD功能

    本文主要介绍了使用SpringBoot集成Redis实现CRUD功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-10-10

最新评论