如何传递用户信息限制Swagger API端点及基于认证结果渲染API
针对你遇到的这两个Swagger技术难题,我分享下实际项目里用过的可行方案,应该能解决你的困扰:
这里核心思路是把用户身份信息传递到Swagger的配置逻辑中,以此过滤用户无权访问的端点,常用的实现方式有两种:
配置Swagger安全机制+接口过滤
你可以给Swagger添加自定义的安全参数(比如请求头里的用户ID或令牌),然后通过OperationFilter来动态过滤接口。举个Spring Boot环境下的代码示例:@Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build() // 添加安全参数,让用户在Swagger页面输入用户标识 .securitySchemes(Collections.singletonList(new ApiKey("X-User-ID", "X-User-ID", "header"))) .securityContexts(Collections.singletonList(SecurityContext.builder() .securityReferences(Collections.singletonList(new SecurityReference("X-User-ID", new AuthorizationScope[0]))) .build())) // 自定义接口过滤器,根据用户信息判断是否展示该接口 .operationFilter((operation, handlerMethod) -> { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String userId = request.getHeader("X-User-ID"); // 这里替换成你的权限校验逻辑,比如根据userId查询用户权限,判断是否能访问当前接口 return userId != null && checkUserPermission(userId, operation); }); } // 示例权限校验方法 private boolean checkUserPermission(String userId, Operation operation) { // 实际业务中可以从数据库/缓存获取用户权限,和接口要求的权限对比 Set<String> userPermissions = getUserPermissionsFromDB(userId); String apiPermission = operation.getNotes(); // 假设把接口权限标识写在ApiOperation的notes里 return userPermissions.contains(apiPermission) || apiPermission == null; }配置后,用户在Swagger页面需要先填写
X-User-ID参数,后端会根据这个标识过滤掉用户无权访问的接口,只展示符合权限的内容。结合现有权限框架联动
如果你的系统已经用了Spring Security这类权限框架,可以直接复用现有逻辑。比如在ApiOperation注解里标记接口所需的角色,然后在Swagger的配置中通过RequestHandlerSelectors过滤出用户有权限的接口:@Bean public Docket api() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Set<String> userRoles = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toSet()); return new Docket(DocumentationType.SWAGGER_2) .select() .apis(input -> { ApiOperation apiOp = input.getHandlerMethod().getMethodAnnotation(ApiOperation.class); if (apiOp == null) return true; // 从ApiOperation的extensions中获取所需角色 String requiredRole = apiOp.extensions().stream() .filter(ext -> "requiredRole".equals(ext.getName())) .map(ext -> ext.value().toString()) .findFirst().orElse(null); return requiredRole == null || userRoles.contains(requiredRole); }) .paths(PathSelectors.any()) .build(); }
这个需求的核心是动态生成Swagger文档,而不是用静态的配置。具体可以分三步实现:
第一步:给Swagger UI添加凭证输入模块
你可以自定义Swagger UI的页面,添加用户名和密码输入框,用户提交后把凭证发送到后端的认证接口。如果是Spring Boot,可以通过修改swagger-ui.html模板(放在resources/static目录下)来实现,或者用前端代码在Swagger加载后注入自定义表单。第二步:后端验证凭证并生成动态Swagger配置
认证接口验证用户名密码通过后,把用户的权限信息存入会话(Session),然后自定义一个接口来动态生成Swagger JSON。示例代码如下:@GetMapping("/v2/api-docs") public ResponseEntity<JsonNode> getDynamicApiDocs(HttpServletRequest request) { // 从会话获取已认证的用户信息 User authenticatedUser = (User) request.getSession().getAttribute("authUser"); if (authenticatedUser == null) { // 未认证时返回401或空文档 return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); } // 根据用户权限生成专属的Docket配置 Docket userDocket = createDocketForAuthenticatedUser(authenticatedUser); // 把Docket转换为Swagger JSON格式 ObjectMapper objectMapper = new ObjectMapper(); JsonNode swaggerJson = objectMapper.valueToTree(userDocket.getDocumentation()); return ResponseEntity.ok(swaggerJson); } private Docket createDocketForAuthenticatedUser(User user) { Set<String> userPermissions = getUserPermissions(user.getId()); return new Docket(DocumentationType.SWAGGER_2) .select() .apis(input -> { // 过滤出用户有权限的接口 ApiOperation apiOp = input.getHandlerMethod().getMethodAnnotation(ApiOperation.class); if (apiOp == null) return true; String apiPermission = apiOp.extensions().stream() .filter(ext -> "permission".equals(ext.getName())) .map(ext -> ext.value().toString()) .findFirst().orElse(null); return apiPermission == null || userPermissions.contains(apiPermission); }) .paths(PathSelectors.any()) .build(); }第三步:Swagger UI动态加载认证后的文档
在自定义的Swagger UI页面中,当用户认证成功后,调用Swagger UI的API重新加载文档。比如用JavaScript代码:// 认证成功后执行 function loadDynamicSwaggerDocs() { const ui = SwaggerUIBundle({ url: "/v2/api-docs", // 指向我们自定义的动态接口 dom_id: '#swagger-ui', presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ] }); ui.initOAuth({}); }
这样就能实现“用户输入凭证→后端验证→根据权限渲染对应Swagger接口”的流程了。
内容的提问来源于stack exchange,提问作者Sharad Ahire




