运行时修改Swagger @Operation注解hidden属性openapi.json未生效问题
注解修改不生效的核心原因
你修改注解后没有同步到openapi.json的核心原因是Swagger的OpenAPI元数据是提前初始化缓存的,具体可拆解为三点:
- Swagger会在应用启动阶段扫描所有接口的
@Operation等注解,将解析后的接口元数据存储到内存缓存中,后续收到openapi.json请求时直接返回缓存的序列化结果,不会重新扫描类注解,你在请求阶段修改的注解值不会作用于已经生成好的缓存数据。 - 你通过反射修改的是注解代理对象的成员值,Swagger内部已经将启动阶段读取到的
hidden属性值存储到了自己的OpenAPI模型中,不会再二次读取注解属性,因此修改不会生效。 - 额外提醒:该反射修改是全局生效的,注解是JVM类层面的共享元数据,一旦修改所有线程都会读到修改后的值,会出现权限泄露的线程安全问题。
正确实现方案
不要通过修改注解实现动态隐藏,应该在OpenAPI文档生成/返回阶段做请求级别的过滤,两种常用实现方式:
方案1:使用Swagger原生自定义过滤器
- SpringBoot+SpringDoc环境:实现
OperationCustomizer接口,在Operation生成阶段根据当前请求上下文的用户权限判断是否设置hidden属性:
@Component public class PermissionOperationCustomizer implements OperationCustomizer { @Override public Operation customize(Operation operation, HandlerMethod handlerMethod) { // 从上下文获取当前用户权限 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 自定义权限判断逻辑,不符合则隐藏接口 if (!checkPermission(auth, handlerMethod)) { operation.setHidden(true); } return operation; } private boolean checkPermission(Authentication auth, HandlerMethod handlerMethod) { // 你的权限校验逻辑 return true; } }
- JAX-RS环境:注册自定义的
OpenApiFilter,在OpenAPI对象序列化前遍历所有path下的operation做权限过滤。
方案2:拦截openapi.json响应动态修改
将你现有的ContainerRequestFilter改为ContainerResponseFilter,拦截openapi.json的响应,将响应体反序列化为OpenAPI对象,根据当前用户权限删除不符合的path或设置operation的hidden属性,再序列化返回即可。该方案完全是请求级别的处理,不存在线程安全问题。
内容的提问来源于stack exchange,提问作者ulrich
相关产品推荐
相关产品推荐

