Java方法级授权检查:无Spring实现自定义注解鉴权可行吗?
当然可以!完全不用依赖Spring这类框架,纯Java就能实现你说的这种方法级权限校验注解。我之前就帮朋友做过类似的实现,核心是用到Java的反射和动态代理(或者运行时反射校验),下面给你一步步拆解实现思路和代码示例:
第一步:定义自定义权限注解
首先我们要先定义一个像@AccessValidator这样的注解,指定它可以作用在方法上,并且是运行时可见的:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // 权限级别枚举 enum AccessLevel { ADMIN, USER, GUEST } // 自定义权限校验注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessValidator { AccessLevel value(); }
第二步:实现权限校验的核心逻辑
接下来写一个工具类,负责读取方法上的注解,并且和当前用户的权限做对比:
public class AccessCheckUtil { // 模拟获取当前登录用户的权限(实际项目里可以从ThreadLocal、上下文等地方拿) private static AccessLevel getCurrentUserAccessLevel() { // 这里只是示例,实际要替换成真实的用户权限获取逻辑 return AccessLevel.USER; } // 校验方法权限的核心方法 public static void checkAccess(Method method) throws SecurityException { // 判断方法上是否有AccessValidator注解 if (method.isAnnotationPresent(AccessValidator.class)) { AccessValidator annotation = method.getAnnotation(AccessValidator.class); AccessLevel requiredLevel = annotation.value(); AccessLevel currentLevel = getCurrentUserAccessLevel(); // 这里简单做级别判断,实际可以扩展更复杂的权限规则 if (!currentLevel.equals(requiredLevel)) { throw new SecurityException("权限不足:需要" + requiredLevel + "权限,当前是" + currentLevel); } } } }
第三步:两种调用方式(手动/自动)
方式一:手动调用校验(简单直接)
在调用目标方法前,手动触发权限校验:
public class DemoService { @AccessValidator(AccessLevel.ADMIN) public void adminOnlyMethod() { System.out.println("执行管理员专属方法"); } public static void main(String[] args) throws Exception { DemoService service = new DemoService(); // 获取目标方法 Method method = DemoService.class.getMethod("adminOnlyMethod"); try { // 先校验权限 AccessCheckUtil.checkAccess(method); // 校验通过再执行方法 method.invoke(service); } catch (SecurityException e) { System.err.println(e.getMessage()); } } }
运行这段代码会抛出权限不足的异常,因为我们模拟的当前用户是USER级别。
方式二:动态代理自动拦截(更优雅)
如果不想每次都手动写校验,可以用JDK动态代理来实现自动拦截方法调用,自动触发校验:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class AccessProxyHandler implements InvocationHandler { private final Object target; public AccessProxyHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 先执行权限校验 AccessCheckUtil.checkAccess(method); // 校验通过后执行原方法 return method.invoke(target, args); } // 创建代理对象的工具方法 public static <T> T createProxy(T target) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new AccessProxyHandler(target) ); } }
然后定义一个接口和实现类来测试:
public interface DemoService { @AccessValidator(AccessLevel.ADMIN) void adminOnlyMethod(); @AccessValidator(AccessLevel.USER) void userMethod(); } public class DemoServiceImpl implements DemoService { @Override public void adminOnlyMethod() { System.out.println("执行管理员专属方法"); } @Override public void userMethod() { System.out.println("执行普通用户方法"); } } // 测试类 public class ProxyTest { public static void main(String[] args) { DemoService realService = new DemoServiceImpl(); DemoService proxyService = AccessProxyHandler.createProxy(realService); try { proxyService.adminOnlyMethod(); // 会抛出权限不足 } catch (Exception e) { System.err.println(e.getMessage()); } try { proxyService.userMethod(); // 可以正常执行 } catch (Exception e) { System.err.println(e.getMessage()); } } }
额外说明
- 如果担心反射的性能问题,可以考虑用编译时注解处理器来生成静态代理类,这样就不用在运行时做反射操作了,不过实现起来会复杂一点。
- 权限规则可以根据实际需求扩展,比如支持多个权限、角色组等,只需要修改
AccessCheckUtil里的校验逻辑就行。
这样一套下来,就完全脱离Spring等框架实现了你想要的方法级权限校验。如果还有细节想调整,都可以在这个基础上灵活扩展。
内容的提问来源于stack exchange,提问作者Lasse
相关产品推荐
相关产品推荐

