You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中如何用类/方法级安全注解替代anyRequest().denyAll()

解决方案

1. 启用方法级安全注解支持

在Spring Security配置类上添加@EnableMethodSecurity注解,开启所需注解支持并设置默认拒绝所有未注解方法:

import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
import org.springframework.context.annotation.Configuration

@EnableMethodSecurity(
    prePostEnabled = true,    // 启用@PreAuthorize/@PostAuthorize
    securedEnabled = true,    // 启用@Secured
    jsr250Enabled = true,     // 启用@RolesAllowed/@PermitAll
    defaultAuthorization = "denyAll()"  // 全局默认:拒绝所有无注解方法
)
@Configuration
class SecurityConfig {
    // 后续过滤器链配置
}

defaultAuthorization = "denyAll()"是Spring Security 6.1+的新增属性,可直接设置全局默认授权规则。若使用更早版本,可通过自定义MethodSecurityExpressionHandler实现相同效果。

2. 调整SecurityFilterChain配置

修改原有过滤器链逻辑,移除denyAll(),让非公共路径请求通过过滤器链后交由方法级安全注解处理:

import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain
import org.springframework.http.HttpMethod
import org.springframework.context.annotation.Bean

@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain =
    http
        .csrf { it.disable() }
        .authorizeHttpRequests { auth ->
            auth
                // 开放公共认证路径
                .requestMatchers(HttpMethod.POST, "/auth/register", "/auth/login")
                .permitAll()
                // 所有其他请求放行至控制器,由方法级安全控制访问
                .anyRequest()
                .permitAll()
        }
        // 其他配置(如认证管理器、JWT过滤器等)...
        .build()

3. 验证注解逻辑(符合需求示例)

示例1:方法级细粒度控制

无注解方法触发默认denyAll(),带注解方法按规则生效:

@RestController
class TodoController(private val todoService: TodoService) {
    
    @RolesAllowed(Role.ADMIN_VALUE)
    @GetMapping("/admin/todos")
    fun method0() = todoService.getAdminTodos()

    @RolesAllowed(Role.ADMIN_VALUE, Role.USER_VALUE)
    @GetMapping("/todos")
    fun method1() = todoService.getUserTodos()

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/todos/my")
    fun method2() = todoService.getMyTodos()

    @PermitAll
    @GetMapping("/todos/public")
    fun method3() = todoService.getPublicTodos()

    // 无注解,默认拒绝访问
    @GetMapping("/todos/secret")
    fun method4() = todoService.getSecretTodos()
}

示例2:控制器类级注解继承

类级注解会应用到所有未单独注解的方法:

// 所有方法允许公共访问
@PermitAll
@RestController
class PublicTodoController

// 所有方法仅允许admin访问
@RolesAllowed(Role.ADMIN_VALUE)
@RestController
class AdminTodoController

// 所有方法仅允许已认证用户访问
@PreAuthorize("isAuthenticated()")
@RestController
class AuthenticatedTodoController

// 无类/方法注解,默认拒绝所有访问
@RestController
class RestrictedTodoController

示例3:方法注解覆盖类注解

方法级注解优先级高于类级注解,直接覆盖类规则:

@PreAuthorize("isAuthenticated()")
@RestController
class TodoController {
    
    // 覆盖类注解:允许公共访问
    @PermitAll
    @GetMapping("/todos/public")
    fun foo() = todoService.getPublicTodos()

    // 继承类注解:需已认证
    @GetMapping("/todos/my")
    fun bar() = todoService.getMyTodos()

    // 覆盖类注解:仅admin可访问
    @Secured(Role.ADMIN_VALUE)
    @GetMapping("/admin/todos")
    fun baz() = todoService.getAdminTodos()
}

关键说明

  • 过滤器链仅负责放行公共路径,其余请求全部交由方法级安全处理,避免denyAll()打断注解解析流程。
  • defaultAuthorization = "denyAll()"确保无注解方法默认拒绝访问,符合"默认禁用所有资源"的核心需求。
  • 注解优先级遵循:方法注解 > 类注解 > 全局默认规则。

内容的提问来源于stack exchange,提问作者aslary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 09:57:07