Spring Security6 教程

Spring Security6 基于注解访问控制

在 Spring Security 体系里,存在若干用于实现访问控制的注解。这些注解默认处于不可用状态,需借助@EnableMethodSecurity(旧版使用 @EnableGlobalMethodSecurity 注解) 注解开启后,方能投入使用。

当程序运行时,若注解设置的访问条件满足,流程会正常推进;一旦条件不满足,系统会抛出 403(权限不足)异常 。

这类注解的使用位置较为灵活,既能够标注在 Service 接口、Service 方法上,也可用于 Controller 类或者 Controller 的方法上。不过,实际开发里,通常会将其应用在控制器方法中,以此来管控对应接口 URL 的访问权限,决定特定请求能否进入接口逻辑 。

@EnableMethodSecurity 注解

@EnableMethodSecurity 是 Spring Security 6.1 中推荐使用的注解,用于启用方法级别的安全控制。它是 @EnableGlobalMethodSecurity 的替代方案,提供了更简洁、更灵活的配置方式,支持基于注解的权限控制(如 @PreAuthorize、@PostAuthorize)以及与新的授权管理器 API 的集成。

该注解允许在服务层或控制器方法上使用安全注解(如 @PreAuthorize、@Secured),实现细粒度的访问控制。

它默认开启如下核心注解:

  • @PreAuthorize  方法执行前进行权限校验。

  • @PostAuthorize  方法执行后基于返回值进行权限校验。

  • @PreFilter/@PostFilter  对集合参数或返回值进行过滤。

注意:通过参数配置可启用 @Secured 和 JSR-250 的 @RolesAllowed 注解。还可以自定义 AuthorizationManager Bean,实现更复杂的授权逻辑。

@EnableMethodSecurity 注解属性说明:

jsr250Enabled

表示是否启用 JSR-250 标准的安全注解(如 @RolesAllowed、@PermitAll、@DenyAll),默认值 false。例如:

@EnableMethodSecurity(jsr250Enabled = true)
public class SecurityConfig {
    // ... 
}

mode

指定安全增强的实现方式:

  • PROXY:基于 Spring AOP 代理(默认),仅支持方法的外部调用。

  • ASPECTJ:基于 AspectJ 织入,支持所有方法调用(包括内部调用)。

例如:

@EnableMethodSecurity(mode = AdviceMode.ASPECTJ)
public class SecurityConfig {
    // ... 
}

offset

当多个增强(Advice)应用于同一连接点时,调整安全拦截器的执行顺序。较小的 offset 值表示优先执行。例如:

@EnableMethodSecurity(offset = -1) // 优先执行安全拦截器
public class SecurityConfig {
    // ... 
}

prePostEnabled

默认值为 true,是否启用 Spring Security 的表达式驱动注解:

  • @PreAuthorize:方法执行前校验权限。

  • @PostAuthorize:方法执行后校验返回值。

  • @PreFilter/@PostFilter:过滤集合参数或返回值。

例如:

@EnableMethodSecurity(prePostEnabled = true) // 默认开启
public class SecurityConfig {
    // ... 
}

proxyTargetClass

指定代理方式:

  • false:基于接口的 JDK 动态代理(默认)。

  • true:基于类的 CGLIB 代理(需引入 CGLIB 依赖)。

例如:

@EnableMethodSecurity(proxyTargetClass = true) // 使用 CGLIB 代理
public class SecurityConfig {
    // ... 
}

securedEnabled

是否启用 Spring Security 的 @Secured 注解(旧版注解,功能较简单),默认为 false。例如:

@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
    // ... 
}

下面是上述属性的一个完整配置:

@Configuration
@EnableMethodSecurity(
    prePostEnabled = true,    // 启用 @PreAuthorize、@PostAuthorize
    securedEnabled = false,   // 禁用 @Secured
    jsr250Enabled = true,     // 启用 @RolesAllowed
    mode = AdviceMode.PROXY,  // 使用 AOP 代理
    proxyTargetClass = false  // 使用 JDK 接口代理
)
public class SecurityConfig {
    // 其他安全配置...
}

@Secured 注解

@Secured 注解是专门用于判断是否具有角色的,能写在方法或类上。@Secured 参数要以 ROLE_ 开头。注意,角色代码注意大小写。

例如:

(1)开启 @Secured 注解功能,如下:

@Configuration
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
    //...
}

(2)使用 @Secured 注解验证角色权限,如下:

@RestController
public class HelloController {
    
    // 用户拥有 normal 角色,可以访问
    //@Secured("role_normal")
    // 用户拥有 admin 或 normal 角色,可以访问
    @Secured({"ROLE_admin", "ROLE_normal"})
    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Security!";
    }

}

 

@PreAuthorize/@PostAuthorize 注解

@PreAuthorize 和 @PostAuthorize 都是方法或类级别注解。

@PreAuthorize 表示访问方法或类在执行之前先判断权限,大多情况下都是使用这个注解,注解的参数和access() 方法参数取值相同,都是权限表达式。

@PostAuthorize 表示方法或类执行结束后判断权限,此注解很少被使用到(代码都执行了,还校验什么权限呢)。

注意:必须在启动类 @EnableGlobalMethodSecurity 中设置 prePostEnabled = true,如下:

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    //...
}

注意,prePostEnabled 默认为 true,如下图:

Spring Security6 基于注解访问控制

@PreAuthorize 示例

在控制器方法上添加 @PreAuthorize,参数可以是任何 access() 支持的表达式。例如:

@RestController
public class HelloController {

    // 请求前验证,如果有 normal 角色,则允许访问
    @PreAuthorize("hasRole('normal')")
    @GetMapping("/hello")
    public String hello() {
        System.out.println("hello()");
        return "Hello, Spring Security!";
    }

}

@PostAuthorize 示例

在控制器方法上添加 @PostAuthorize,参数可以是任何 access() 支持的表达式。例如:

@RestController
public class HelloController {

    // 请求后验证,如果拥有 admin 角色才能访问
    @PostAuthorize("hasRole('admin')")
    @GetMapping("/hello")
    public String hello() {
        System.out.println("hello()");
        return "Hello, Spring Security!";
    }

}

运行后如下图:

Spring Security6 基于注解访问控制

从上图可知,访问 /hello,后端执行了 hello() 代码,但是并没有通过权限校验。

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号