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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 11:27:03