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

Spring中如何将自定义注解的参数值注入到@PreAuthorize注解中?

实现方案

方案1:直接改造@AllowAccessTo注解的SpEL表达式(推荐,无需额外编码)

这是最简便的实现方式,仅需修改自定义注解上的@PreAuthorize的SpEL表达式,借助Spring Security方法安全上下文内置的method对象和Spring自带的AnnotationUtils工具类,就能自动获取到你传入的权限标识:

import org.springframework.security.access.prepost.PreAuthorize;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
// 注意替换下列表达式中的「com.example.annotation.AllowAccessTo」为你自己注解的全限定类名
@PreAuthorize("hasAnyAuthority(@authorityService.getPrivilege(T(org.springframework.core.annotation.AnnotationUtils).findAnnotation(#this.method, T(com.example.annotation.AllowAccessTo)).value()))")
public @interface AllowAccessTo {
    String value() default "";
}

说明:

  • 表达式中的#this.method是Spring Security方法安全SpEL上下文内置的对象,代表当前被调用的接口方法
  • AnnotationUtils.findAnnotation会优先查找方法上的@AllowAccessTo注解,方法上不存在时自动查找类上的注解,完美适配注解加在方法或类上的场景
  • 你不需要修改Controller层的原有注解用法,保持@AllowAccessTo("GET_ALL_STUDENT")的写法即可直接生效

方案2:自定义方法安全切面(适合复杂权限校验场景)

如果你后续需要扩展更复杂的权限校验逻辑,可以单独写一个切面处理@AllowAccessTo注解,完全自主控制校验逻辑:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AllowAccessToAspect {

    private final AuthorityService authorityService;

    // 构造注入你的权限服务
    public AllowAccessToAspect(AuthorityService authorityService) {
        this.authorityService = authorityService;
    }

    // 注意替换包路径为你自己的@AllowAccessTo注解所在路径
    @Around("@within(com.example.annotation.AllowAccessTo) || @annotation(com.example.annotation.AllowAccessTo)")
    public Object checkPermission(ProceedingJoinPoint pjp) throws Throwable {
        AllowAccessTo annotation = AnnotationUtils.findAnnotation(
                ((MethodSignature)pjp.getSignature()).getMethod(), 
                AllowAccessTo.class
        );
        if (annotation == null) {
            annotation = AnnotationUtils.findAnnotation(
                    pjp.getSignature().getDeclaringType(), 
                    AllowAccessTo.class
            );
        }
        if (annotation == null) {
            return pjp.proceed();
        }
        // 自行实现权限校验逻辑
        String requiredPrivilege = authorityService.getPrivilege(annotation.value());
        boolean hasPermission = SecurityContextHolder.getContext().getAuthentication()
                .getAuthorities()
                .stream()
                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(requiredPrivilege));
        if (!hasPermission) {
            throw new AccessDeniedException("无权限访问该接口");
        }
        return pjp.proceed();
    }
}

使用该方案可以去掉@AllowAccessTo上的@PreAuthorize元注解,所有权限校验逻辑完全由切面控制,灵活性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:09:00