跳至主要內容

AuthorizationFilter

Jin大约 5 分钟

AuthorizationFilter

1、概述

AuthorizationFilter 在整个安全框架中主要负责授权相关的处理。具体来说,AuthorizationFilter 的工作是确定当前请求是否具有访问某个资源的权限。如果用户没有足够的权限访问某个受保护的资源,AuthorizationFilter 将会阻止请求的继续,返回适当的错误响应(如 HTTP 403 Forbidden)。

2、作用

AuthorizationFilter 主要用于:

  • 授权检查:它检查用户是否有足够的权限来访问特定的资源或执行某个操作。如果用户未被授权,它将阻止请求,并返回 403 错误。
  • 角色或权限控制:根据请求的路径、方法、用户角色或权限等信息来决定用户是否有权访问某个资源。
  • 集成自定义权限控制:可以根据具体的业务逻辑进行自定义的权限校验。

3、工作流程

AuthorizationFilter 主要处理的是基于用户的身份(身份验证)来进行资源的授权控制。它的工作流程如下:

3.1、 拦截请求

当一个 HTTP 请求到达过滤器链时,AuthorizationFilter 会根据配置的 URL 路径或方法来确定是否需要进行授权检查。默认情况下,Spring Security 的授权过滤器通常会配置为拦截所有需要权限检查的请求。

3.2、授权校验

AuthorizationFilter 会根据用户的身份信息(通常通过 SecurityContext 中的 Authentication 对象)来检查用户是否具有访问当前请求资源的权限。授权的依据可以是:

  • 用户的角色(如 ROLE_USERROLE_ADMIN
  • 用户的权限(如 READ_PRIVILEGEWRITE_PRIVILEGE
  • 配置的 URL 访问控制规则(例如,/admin/** 需要 ROLE_ADMIN

如果 Authentication 对象为空(即用户未认证),或者用户没有足够的权限,AuthorizationFilter 将会拒绝该请求。

3.3、请求继续或终止

  • 如果授权通过AuthorizationFilter 允许请求继续传递到下一个过滤器或最终的处理方法。
  • 如果授权失败AuthorizationFilter 会生成一个适当的响应,通常是 403 Forbidden,表示当前用户没有权限访问该资源。

3.4、调用 AccessDeniedHandler(如果没有权限)

当用户没有权限访问某个资源时,AuthorizationFilter 会触发 AccessDeniedHandler 进行进一步的处理。默认情况下,Spring Security 会返回一个 HTTP 403 状态码响应,表示资源不可访问。

4、配置和使用

在 Spring Security 中,AuthorizationFilter 主要由 http.authorizeRequests() 进行配置。你可以基于角色、权限、请求路径等进行授权控制。常见的配置项包括:

  • 角色/权限控制:通过 .hasRole().hasAuthority() 等方法指定特定的角色或权限要求。
  • 请求路径控制:通过 .antMatchers().requestMatchers() 配置受保护的路径。

4.1、示例 1:基于角色进行授权控制

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.InMemoryUserDetailsManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        // 使用内存中的用户管理服务创建一个用户
        return new InMemoryUserDetailsManager(
                User.withUsername("user")
                    .password("{noop}password")  // 密码无需加密,使用 {noop} 表示
                    .roles("USER")
                    .build(),
                User.withUsername("admin")
                    .password("{noop}admin")
                    .roles("ADMIN")
                    .build()
        );
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")  // 只有具有 ADMIN 角色的用户可以访问 /admin/**
                .antMatchers("/user/**").hasRole("USER")    // 只有具有 USER 角色的用户可以访问 /user/**
                .anyRequest().authenticated()             // 其他请求需要认证
            .and()
            .formLogin();  // 启用表单登录

        return http.build();
    }
}

解释:

  1. authorizeRequests():配置请求的访问控制。antMatchers() 用于指定 URL 模式,hasRole() 用于指定角色要求。
  2. formLogin():启用默认的表单登录机制,用户可以通过表单进行身份验证。
  3. 用户通过 useradmin 登录后,AuthorizationFilter 会检查他们是否有足够的权限访问 /admin/**/user/** 资源。

4.2、示例 2:基于权限进行授权控制

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        // 配置用户及其权限
        return new InMemoryUserDetailsManager(
                User.withUsername("reader")
                    .password("{noop}password")
                    .authorities("READ_PRIVILEGE")
                    .build(),
                User.withUsername("writer")
                    .password("{noop}password")
                    .authorities("WRITE_PRIVILEGE")
                    .build()
        );
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/read/**").hasAuthority("READ_PRIVILEGE")   // 只有具有 READ_PRIVILEGE 权限的用户可以访问 /read/**
                .antMatchers("/write/**").hasAuthority("WRITE_PRIVILEGE") // 只有具有 WRITE_PRIVILEGE 权限的用户可以访问 /write/**
                .anyRequest().authenticated()                           // 其他请求需要认证
            .and()
            .formLogin();  // 启用表单登录
        return http.build();
    }
}

解释:

  1. hasAuthority():用于基于权限进行授权控制,与角色不同,权限一般通过 authorities 来分配。
  2. 配置了两个用户:reader 用户有 READ_PRIVILEGE 权限,writer 用户有 WRITE_PRIVILEGE 权限。
  3. AuthorizationFilter 会根据这些权限检查用户是否能够访问 /read/**/write/**

4.3、示例 3:授权失败处理(AccessDeniedHandler

Spring Security 6.x 允许你自定义授权失败的处理方式。例如,当用户访问某个受保护的资源时没有足够的权限,系统会返回 403 Forbidden 错误。

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.InMemoryUserDetailsManager;
import org.springframework.web.bind.annotation.ResponseStatus;

@Configuration
public class SecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        return new InMemoryUserDetailsManager(
                User.withUsername("user")
                    .password("{noop}password")
                    .roles("USER")
                    .build()
        );
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .exceptionHandling()
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                        response.sendError(HttpStatus.FORBIDDEN.value(), "Access Denied");
                    }
                });
        return http.build();
    }
}

解释:

  1. exceptionHandling().accessDeniedHandler():设置自定义的 AccessDeniedHandler,当用户未授权访问资源时,返回 403 错误。
  2. 当用户访问 /admin/** 并且没有 ADMIN 角色时,AuthorizationFilter 会调用 AccessDeniedHandler 返回 403 错误。

4.4、基于自定义表达式的授权控制

如果你需要更加精细的授权控制,例如基于 URL 模式和复杂的条件判断,你可以通过 authorizeHttpRequests() 进行更加灵活的配置。例如:

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    // 配置内存中的用户详情服务
    @Bean
    public UserDetailsService userDetailsService() {
        return new InMemoryUserDetailsManager(
                User.withUsername("user")
                    .password("{noop}password")
                    .roles("USER")
                    .build(),
                User.withUsername("admin")
                    .password("{noop}admin")
                    .roles("ADMIN")
                    .build()
        );
    }

    // 配置 HTTP 安全,支持自定义授权表达式
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/admin/**").hasRole("ADMIN")  // 仅允许 ADMIN 角色访问 /admin/**
                    .antMatchers("/user/**").hasRole("USER")    // 仅允许 USER 角色访问 /user/**
                    .antMatchers("/**").access("hasRole('USER') and hasAuthority('WRITE_PRIVILEGE')") // 复杂的授权表达式
                    .anyRequest().authenticated()
            )
            .formLogin();  // 启用表单登录

        return http.build();
    }
}

5. AuthorizationFilterFilterSecurityInterceptor

FilterSecurityInterceptor 被弃用,AuthorizationFilter 的授权逻辑通过 SecurityFilterChainHttpSecurity 来配置。在 SecurityFilterChain 中,你可以通过 authorizeHttpRequests() 来设置路径访问控制、角色/权限验证等规则,AuthorizationFilter 会根据这些规则执行授权检查,并且通过 AccessDecisionManager 来做出授权决策。

贡献者: Jin