如何在Keycloak扩展中用Swagger/OpenAPI生成自定义API文档?
解决Keycloak自定义扩展Swagger/OpenAPI文档不显示问题
1. 核心问题分析
Keycloak扩展作为插件部署,并非独立Quarkus应用,因此不会自动读取扩展内的application.properties,且默认的OpenAPI扫描逻辑不会覆盖扩展中的JAX-RS资源,这是文档无法生成的核心原因。
2. 为自定义JAX-RS资源添加OpenAPI注解
确保你的资源类和方法上正确标注SmallRye OpenAPI注解,让扫描机制识别API信息:
import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.jboss.resteasy.annotations.cache.NoCache; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("custom") public class CustomRealmResource { @GET @NoCache @Produces(MediaType.APPLICATION_JSON) @Operation(summary = "获取自定义领域数据", description = "返回当前领域的自定义业务信息") @APIResponse(responseCode = "200", description = "成功获取数据") public String getCustomData( @Parameter(description = "目标领域ID", required = true) @PathParam("realm") String realm) { return "{\"message\": \"Custom data for realm " + realm + "\"}"; } }
3. 手动暴露OpenAPI文档端点
Keycloak不会自动扫描扩展资源生成文档,需要自定义资源来暴露OpenAPI模型:
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; import org.eclipse.microprofile.openapi.annotations.info.Info; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.resteasy.annotations.cache.NoCache; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.eclipse.microprofile.openapi.models.OpenAPI; import org.eclipse.microprofile.openapi.OASFactory; @OpenAPIDefinition( info = @Info(title = "Keycloak自定义领域API", version = "1.0.0"), tags = @Tag(name = "custom", description = "自定义领域业务接口") ) @Path("openapi") public class CustomOpenApiResource { @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public OpenAPI getOpenApi() { // 可通过SmallRye API自动扫描扩展内的JAX-RS资源,此处示例为手动构建 return OASFactory.createObject(OpenAPI.class) .info(OASFactory.createInfo() .title("Keycloak自定义领域API") .version("1.0.0")); } }
将这个类通过RealmResourceProviderFactory注册后,即可通过/admin/realms/{realm}/openapi访问JSON格式的OpenAPI文档。
4. 部署自定义Swagger UI
复用Keycloak内置的Swagger UI资源,自定义入口页面指向你的OpenAPI文档:
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("swagger-ui") public class CustomSwaggerUiResource { @GET @Produces(MediaType.TEXT_HTML) public Response getSwaggerUi() { String html = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "<head>\n" + " <meta charset=\"UTF-8\">\n" + " <title>自定义Keycloak API文档</title>\n" + " <link rel=\"stylesheet\" type=\"text/css\" href=\"/admin/swagger-ui/swagger-ui.css\" />\n" + " <script src=\"/admin/swagger-ui/swagger-ui-bundle.js\"></script>\n" + " <script src=\"/admin/swagger-ui/swagger-ui-standalone-preset.js\"></script>\n" + "</head>\n" + "<body>\n" + " <div id=\"swagger-ui\"></div>\n" + " <script>\n" + " window.onload = function() {\n" + " const realm = window.location.pathname.split('/')[3];\n" + " const ui = SwaggerUIBundle({\n" + " url: `${window.location.origin}/admin/realms/${realm}/openapi`,\n" + " dom_id: '#swagger-ui',\n" + " presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n" + " layout: \"StandaloneLayout\"\n" + " });\n" + " };\n" + " </script>\n" + "</body>\n" + "</html>"; return Response.ok(html).build(); } }
注册后,通过/admin/realms/{realm}/swagger-ui即可访问自定义API的Swagger UI界面。
5. 依赖版本适配
确保扩展使用的SmallRye OpenAPI版本与Keycloak内置版本一致,避免冲突,建议使用provided scope复用Keycloak的依赖:
<dependency> <groupId>io.smallrye</groupId> <artifactId>smallrye-open-api-jaxrs</artifactId> <version>${smallrye-open-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-swagger-ui</artifactId> <version>${quarkus.version}</version> <scope>provided</scope> </dependency>
版本号可参考Keycloak官方BOM文件。
内容的提问来源于stack exchange,提问作者AmiR
相关产品推荐
相关产品推荐

