Java注解本身是元数据标记,需结合反射与AOP在运行时读取并执行校验;微服务中统一鉴权依赖网关认证+请求头透传+业务服务AOP拦截校验,路由则由网关配置驱动而非Java注解。

Java 注解本身不执行逻辑,它只是元数据标记;真正起作用的是配合反射 + AOP(或 Spring 的拦截器、过滤器)在运行时读取注解并执行校验。在微服务中实现统一的路由与鉴权注解,关键不是“写注解”,而是构建一套可复用、可集中管理、上下游协同的信任链路。
路由注解:靠网关解析路径,不是靠 Java 注解
Spring Cloud Gateway 本身不识别 @RequestMapping 这类 Controller 层注解来做路由——那是 Spring MVC 的事。网关路由靠的是配置(YAML)或 RouteLocator 编程式定义,比如:
- Path=/user/** → 转发到 user-service
- Path=/order/{id} → 提取 id 做灰度或限流参数
所以“路由注解”在微服务架构里通常不指 Java 类上的注解,而是指:在网关层通过路径规则 + Predicate 实现语义化路由。如果你真想用注解驱动路由,需自研一套机制:在启动时扫描所有 @RouteMapping("v1/pay") 的 Controller 方法,自动注册为 Gateway Route ——但这样做会破坏网关与业务服务的解耦,不推荐。
鉴权注解:核心是“谁解析、谁执行、谁信任”
鉴权注解(如 @RequiresPermissions("user:delete"))要生效,必须满足三个条件:
立即学习“Java免费学习笔记(深入)”;
- 网关已完成身份认证:JWT 已被网关校验签名、有效期,并把 userId、roles、perms 等信息以请求头(如 X-User-ID、X-Roles)透传给下游
- 业务服务信任网关头信息:不再自己解析 JWT,只从请求头取用户上下文,避免重复鉴权和密钥泄露风险
- 注解由统一拦截器/AOP 执行:比如一个全局 @Aspect 切面,读取方法上的 @RequiresPermissions,再调用 PermissionService.check(userId, "user:delete")
示例流程:客户端带 Bearer token 请求 /user/123 → Gateway 校验通过 → 添加 Header X-User-ID:1001,X-Roles:USER → 下游 user-service 收到请求 → AuthAspect 拦截 @RequiresPermissions("user:read") → 从 Header 取 1001 → 查 DB 或缓存确认该用户有 user:read 权限 → 放行或抛 403。
统一注解体系的关键设计点
要让注解在多个微服务中行为一致,不能每个服务各自实现一套校验逻辑。推荐做法:
- 定义公共注解模块:新建 common-auth-starter,包含 @RequiresLogin、@RequiresRole、@RequiresPermissions 等注解定义,所有服务引入该依赖
- 提供标准拦截器 Bean:starter 中内置 SaInterceptor(若用 Sa-Token)或自研 AuthAspect,自动注册进 Spring 容器,开箱即用
- 权限判断委托给独立权限服务:不查本地数据库,而是调用 auth-permission-service 的 HTTP 接口或 Dubbo 方法,确保权限策略中心化、实时生效
- 支持表达式扩展:像 @PreAuthorize("hasPermission(#id, 'order:write')") 这类 SpEL 表达式,需搭配 MethodSecurityExpressionHandler 使用,适合复杂资源级鉴权
为什么不建议在网关层做注解鉴权?
网关是响应式(Reactor)模型,没有 Controller 方法上下文,无法直接获取 @RequiresPermissions 的目标方法和参数。强行在 GatewayFilter 里做注解扫描+反射,会导致:
- 无法访问下游服务的类信息(字节码未加载)
- 无法绑定请求参数(如 @PathVariable id)参与权限判断
- 违背“网关只做认证、业务服务做鉴权”的分层原则
正确分工是:网关管「你是谁」(Who),业务服务管「你能干啥」(What)。注解天然属于业务语义层,理应由业务服务承载。



















