侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现基于反射和注解的运行时方法权限校验框架

2025-12-13 / 0 评论 / 7 阅读

题目

实现基于反射和注解的运行时方法权限校验框架

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

自定义注解设计,反射动态代理,运行时方法拦截,权限校验逻辑,异常处理

快速回答

实现步骤:

  1. 定义@RequiresPermission注解标记需要权限校验的方法
  2. 创建动态代理拦截带注解的方法
  3. 通过反射获取方法上的注解信息
  4. 实现权限校验逻辑(如RBAC模型)
  5. 处理校验失败异常并返回友好提示

核心代码:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresPermission {
    String value();
}
## 解析

问题背景

在分布式系统中,需要实现细粒度的权限控制。要求通过自定义注解和反射机制,在方法执行前动态校验当前用户权限。

解决方案

1. 定义权限注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresPermission {
    // 权限标识符
    String value();

    // 权限校验失败时的错误码(可选)
    int errorCode() default 403;
}

2. 实现动态代理拦截

public class SecurityProxy implements InvocationHandler {
    private final Object target;
    private final UserContext userContext; // 当前用户上下文

    public static Object newInstance(Object obj, UserContext context) {
        return Proxy.newProxyInstance(
            obj.getClass().getClassLoader(),
            obj.getClass().getInterfaces(),
            new SecurityProxy(obj, context)
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 检查方法注解
        if (method.isAnnotationPresent(RequiresPermission.class)) {
            RequiresPermission ann = method.getAnnotation(RequiresPermission.class);
            if (!userContext.hasPermission(ann.value())) {
                throw new AccessDeniedException("ErrorCode: " + ann.errorCode());
            }
        }
        return method.invoke(target, args);
    }
}

3. 业务层使用示例

public interface OrderService {
    @RequiresPermission("order:delete")
    void deleteOrder(String orderId);
}

// 使用代理
OrderService service = (OrderService) SecurityProxy.newInstance(
    new OrderServiceImpl(), 
    currentUser
);
service.deleteOrder("123"); // 自动触发权限校验

关键原理

  • 注解保留策略RetentionPolicy.RUNTIME确保注解在运行时可通过反射获取
  • 动态代理机制:通过Proxy.newProxyInstance创建代理对象拦截方法调用
  • 方法注解扫描Method.isAnnotationPresent()检测目标方法是否携带指定注解

最佳实践

  1. 性能优化:缓存带注解的方法集合,避免每次调用都反射扫描
  2. 权限模型扩展:支持权限表达式如@RequiresPermission("order:delete:#orderId")
  3. 组合注解:定义@AdminOnly等组合注解简化常用权限配置

常见错误

错误类型后果解决方案
未设置@Retention(RUNTIME)运行时无法获取注解确认注解保留策略
代理非接口方法JDK动态代理失效使用CGLIB或改为接口代理
忽略桥接方法泛型方法校验失败调用method.getDeclaredAnnotations()

扩展知识

  • Spring AOP实现:可通过@Around切面+ProceedingJoinPoint实现相同功能
  • 注解继承问题:默认不继承接口注解,需使用@Inherited
  • 性能对比:反射调用比直接调用慢50-100倍,高频场景考虑字节码增强方案