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
相关产品推荐
相关产品推荐

