乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Spring Security 基础

    • 本章定位
    • Spring Security 是什么
    • DelegatingFilterProxy
    • 安全过滤器链
    • SecurityFilterChain
    • 过滤器执行顺序
  • 第2章 认证

    • 本章定位
    • Authentication
    • 认证流程
    • AuthenticationManager
    • ProviderManager
    • DaoAuthenticationProvider
    • UserDetails
    • UserDetailsService
    • PasswordEncoder
    • BCryptPasswordEncoder
    • DelegatingPasswordEncoder
    • 表单登录
    • SecurityContext
    • SecurityContextHolder
    • UsernamePasswordAuthenticationToken
  • 第3章 授权

    • 本章定位
    • 授权模型
    • GrantedAuthority
    • AccessDecisionManager
    • AccessDecisionVoter
    • URL 级别授权
    • 方法级别安全
    • @PreAuthorize
    • @PostAuthorize
    • @PreFilter
    • @PostFilter
    • @Secured
    • RoleHierarchy
  • 第4章 过滤器链

    • 本章定位
    • FilterChainProxy
    • SecurityContextHolderFilter
    • LogoutFilter
    • BasicAuthenticationFilter
    • CsrfFilter
    • CorsFilter
    • HeaderWriterFilter
    • AnonymousAuthenticationFilter
    • RequestCacheAwareFilter
    • ExceptionTranslationFilter
    • FilterSecurityInterceptor
  • 第5章 会话管理

    • 本章定位
    • 会话管理
    • SessionFixation
    • 会话并发控制
    • SessionCreationPolicy
    • RememberMe
  • 第6章 JWT

    • 本章定位
    • JWT
    • JwtDecoder
    • JWT 认证
    • JwtAuthenticationConverter
  • 第7章 OAuth2

    • 本章定位
    • OAuth2 基础
    • OAuth2 Client
    • OAuth2 Resource Server
    • 第三方登录配置
  • 第8章 攻击防护

    • 本章定位
    • CSRF 跨站请求伪造防护
    • CORS 跨域防护
    • Clickjacking 点击劫持防护
    • 安全响应头
    • Session Fixation 会话固定防护
  • 第9章 测试

    • 本章定位
    • 安全测试
    • @WithMockUser
    • 最佳实践

授权模型

一句话定义:Spring Security 的授权体系从请求到达受保护资源的路径上,通过 URL 级、方法级、实例级 三个粒度层层拦截,形成纵深防御的访问控制模型。


定义与作用

授权(Authorization)解决"你能做什么"的问题。Spring Security 提供三个递进的授权粒度:

粒度拦截位置适用场景核心组件
URL 级别Servlet 过滤器链末尾(FilterSecurityInterceptor / AuthorizationFilter)Web 资源的粗粒度控制,如 /admin/** 需管理员角色HttpSecurity + AccessDecisionManager
方法级别AOP 方法拦截器(MethodSecurityInterceptor)Service 层业务方法的细粒度控制,如删除订单需特定权限@EnableGlobalMethodSecurity + 注解
实例级别方法级别注解中通过 SpEL 表达式引用对象属性数据行级控制,如"只能查看自己的订单"@PostAuthorize + returnObject

三层授权的关系:


核心原理

三层拦截的执行顺序

Spring Security 的授权决策按以下顺序执行:

  1. URL 级别:请求进入 FilterSecurityInterceptor(Spring Security 5.x)或 AuthorizationFilter(6.x),从 SecurityMetadataSource 获取当前 URL 所需的 ConfigAttribute,调用 AccessDecisionManager 投票决策。
  2. 方法级别:若 URL 放行,请求到达 Controller/Service。带有 @PreAuthorize 等方法安全注解的方法,会被 MethodSecurityInterceptor(基于 Spring AOP)拦截,再次执行授权决策。
  3. 实例级别:在方法级别注解中,通过 SpEL 表达式(如 returnObject.owner == authentication.name)对返回对象的属性进行判断,实现数据行级过滤。

示例一:三层授权完整配置

场景说明

电商后台管理系统,要求:

  • /admin/** 仅允许 ADMIN 角色访问(URL 级别)
  • 删除订单方法需 ORDER_DELETE 权限(方法级别)
  • 查询订单只能返回当前用户创建的订单(实例级别)

操作前配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 开启方法级别安全
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(auth -> auth
                .antMatchers("/admin/**").hasRole("ADMIN")     // URL 级别
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin").password("{noop}admin").roles("ADMIN")
            .and()
            .withUser("user").password("{noop}user").roles("USER");
    }
}
@Service
public class OrderService {

    // 方法级别:需要 ORDER_DELETE 权限
    @PreAuthorize("hasAuthority('ORDER_DELETE')")
    public void deleteOrder(Long orderId) {
        // 删除订单逻辑
    }

    // 实例级别:只能返回当前用户的订单
    @PostFilter("filterObject.owner == authentication.name")
    public List<Order> getMyOrders() {
        return orderRepository.findAll();  // 查询全部,但会被过滤
    }
}

操作后配置

通过 Admin 用户访问:

  • GET /admin/orders → 200 OK(URL 级通过)
  • orderService.deleteOrder(1L) → 如果 Admin 拥有 ORDER_DELETE 权限则成功,否则 403
  • orderService.getMyOrders() → 返回 Admin 创建的订单列表

通过 User 用户访问:

  • GET /admin/orders → 403 Forbidden(URL 级拦截)
  • 不会触发方法级别和实例级别拦截

示例二:仅 URL 级别 vs 方法级别配合

场景说明

对比两种配置策略:仅 URL 级别控制 和 URL + 方法级别联合控制。

操作前配置(仅 URL 级别,存在越权漏洞)

@Configuration
@EnableWebSecurity
public class UnsafeConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(auth -> auth
                .antMatchers("/api/orders/**").authenticated()  // 只要登录就能访问
                .anyRequest().permitAll()
            )
            .httpBasic(withDefaults());
    }
}

@Service
public class UnsafeOrderService {
    // 无方法级别安全,任何登录用户都能调用
    public void cancelOrder(Long orderId) {
        // 取消他人订单的漏洞!
    }
}

结果分析:攻击者登录普通用户账号,调用 POST /api/orders/123/cancel,可以取消别人的订单。

操作后配置(URL + 方法级别联合防护)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SafeConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(auth -> auth
                .antMatchers("/api/orders/**").authenticated()
                .anyRequest().permitAll()
            )
            .httpBasic(withDefaults());
    }
}

@Service
public class SafeOrderService {
    // 方法级别:只能取消自己的订单
    @PreAuthorize("hasRole('ADMIN') or @orderSecurityService.isOwner(#orderId, authentication.name)")
    public void cancelOrder(Long orderId) {
        // 安全的取消逻辑
    }
}

@Component
public class OrderSecurityService {
    public boolean isOwner(Long orderId, String username) {
        return orderRepository.findById(orderId)
            .map(order -> order.getOwner().equals(username))
            .orElse(false);
    }
}

结果分析:

  • 普通用户调用 cancelOrder(123) 时,如果订单 123 不是自己创建的 → 403
  • Admin 用户 → 可以取消任何订单
  • 方法级别授权提供了 URL 级别无法实现的细粒度控制

易错场景:URL 级别放行后误以为"完全安全"

场景:开发者配置了 antMatchers("/api/**").authenticated(),认为只要登录就能访问 API,于是在 Service 层不做任何权限检查。

问题:authenticated() 只验证"是否登录",不验证"是谁"。任何登录用户都能调用所有 API,包括管理员专属接口。

正确做法:

// 错误:仅验证登录
.antMatchers("/api/admin/**").authenticated()

// 正确:同时验证角色
.antMatchers("/api/admin/**").hasRole("ADMIN")

面试考点:

问:Spring Security 中 authenticated() 和 hasRole("ADMIN") 有什么区别? 答:authenticated() 只要求用户已登录(非匿名),不检查具体角色;hasRole("ADMIN") 要求用户已登录且拥有 ROLE_ADMIN 权限。生产环境中,绝不能用 authenticated() 替代角色检查,必须按最小权限原则配置 URL 规则或叠加方法级别安全。


三层模型速查表

层级拦截器配置方式最小权限原则
URL 级FilterSecurityInterceptorHttpSecurity.authorizeRequests()越精确的路径越靠前配置
方法级MethodSecurityInterceptor@PreAuthorize / @Secured在 Service 层保护核心业务方法
实例级SpEL 表达式returnObject / filterObject数据所有权校验放在 @PostAuthorize / @PostFilter
上一页
本章定位
下一页
GrantedAuthority