如何在Java SE 11中使用自定义注解?基于反射实现接口权限校验
Spring Boot 自定义@AccessedBy注解权限校验实现方案
你可以通过Spring AOP + Java反射API实现注解的自动校验,完全复用你原有逻辑,不需要在每个Controller手动写校验代码,具体实现步骤如下:
1. 引入AOP依赖
首先在pom.xml中引入Spring AOP起步依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
如果是Gradle项目则引入对应依赖即可。
2. 编写全局权限校验切面
切面类会自动拦截所有Controller方法,通过反射读取方法上的@AccessedBy注解并执行校验逻辑:
import com.sap.vt.recruitment.enumeration.RoleType; 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.AnnotatedElementUtils; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.naming.AccessDeniedException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; @Aspect @Component public class AccessedByAspect { @Resource private RecruitmentFactory recruitmentFactory; // 注入你原有的权限工具类 // 切点配置:拦截所有带@RestController注解的类下的所有方法 @Around("@within(org.springframework.web.bind.annotation.RestController)") public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable { // 1. 通过反射获取当前执行的方法对象 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); // 2. 读取方法上的@AccessedBy注解,支持Spring @AliasFor别名解析 AccessedBy accessedBy = AnnotatedElementUtils.findMergedAnnotation(method, AccessedBy.class); // 方法没有加注解则直接放行,你也可以调整为默认必须加注解,否则拦截 if (accessedBy == null) { return joinPoint.proceed(); } // 3. 复用原有逻辑校验用户是否为内部用户 boolean isInternalUser = recruitmentFactory.getPermission().isInternalUser(); if (!isInternalUser) { throw new AccessDeniedException("用户无访问权限"); } // 4. 获取注解配置的角色列表,校验角色权限 List<RoleType> allowedRoles = Arrays.asList(accessedBy.roleType()); // 调用你原有的角色校验逻辑,比如校验当前用户角色是否在allowedRoles范围内 boolean hasRole = recruitmentFactory.getPermission().checkUserRole(allowedRoles); if (!hasRole) { throw new AccessDeniedException("用户角色不匹配"); } // 校验通过,执行原方法 return joinPoint.proceed(); } }
反射API原生使用说明
如果不使用Spring提供的注解工具类,用原生Java反射读取注解的写法如下:
// 原生反射获取注解,注意原生不支持@AliasFor,需要手动处理别名映射 AccessedBy accessedBy = method.getAnnotation(AccessedBy.class); RoleType[] roles; if (accessedBy.roleType().length > 0) { roles = accessedBy.roleType(); } else { roles = accessedBy.value(); }
更推荐用Spring的AnnotatedElementUtils,可以自动处理@AliasFor的别名映射,不需要手动判断属性优先级。
3. 全局异常处理(可选)
你可以新增全局异常处理器捕获权限校验抛出的异常,统一返回403响应:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<Map<String, Object>> handleAccessDenied(AccessDeniedException e) { Map<String, Object> res = new HashMap<>(); res.put("code", 403); res.put("msg", e.getMessage()); return ResponseEntity.status(HttpStatus.FORBIDDEN).body(res); } }
4. 注解使用示例
直接在Controller接口方法上加注解即可:
// 默认仅超级管理员可访问 @GetMapping("/test1") @AccessedBy public String test1() { return "test1"; } // 指定多个角色可访问 @PostMapping("/test2") @AccessedBy(roleType = {RoleType.SUPER_ADMIN, RoleType.HR}) public String test2() { return "test2"; }
内容的提问来源于stack exchange,提问作者Sugata Kar
相关产品推荐
相关产品推荐

