如何基于Kong OIDC传递的x-userinfo头在Quarkus中实现自定义认证
基于Kong OIDC透传头的Quarkus身份认证实现方案
Kong完成OIDC认证后会将用户信息通过x-userinfo请求头透传给下游Quarkus应用,你可以通过以下步骤实现基于该头的身份认证:
1. 引入核心依赖
首先在项目中引入Quarkus安全相关基础依赖,以Maven为例:
<dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security</artifactId> </dependency> <!-- REST层依赖,根据你项目实际使用的框架引入即可 --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-reactive-jackson</artifactId> </dependency> </dependencies>
2. 定义用户信息映射实体
根据你x-userinfo头内的JSON结构定义对应实体类,用于反序列化:
public class UserInfo { // 用户唯一标识,对应OIDC的sub字段 private String sub; private String email; private String name; // 用户权限角色列表 private List<String> roles; // 按需添加其他字段,补全getter、setter方法 }
3. 实现认证拦截器
通过优先级最高的认证层拦截器解析请求头,构造Quarkus安全上下文:
import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.security.runtime.QuarkusSecurityIdentity; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.Priorities; import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import com.fasterxml.jackson.databind.ObjectMapper; @Provider @Priority(Priorities.AUTHENTICATION) @ApplicationScoped public class KongHeaderAuthFilter implements ContainerRequestFilter { private final ObjectMapper objectMapper; // 注入Jackson序列化工具 public KongHeaderAuthFilter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public void filter(ContainerRequestContext requestContext) { String userInfoHeader = requestContext.getHeaderString("x-userinfo"); // 头不存在直接返回401未认证 if (userInfoHeader == null || userInfoHeader.isBlank()) { requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); return; } UserInfo userInfo; try { // 若你的x-userinfo是Base64编码,需要先解码再反序列化: // userInfoHeader = new String(Base64.getDecoder().decode(userInfoHeader)); userInfo = objectMapper.readValue(userInfoHeader, UserInfo.class); } catch (Exception e) { requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); return; } // 构造安全上下文 SecurityIdentity identity = QuarkusSecurityIdentity.builder() .setPrincipal(() -> userInfo.getSub()) .addRoles(userInfo.getRoles()) .addAttribute("fullUserInfo", userInfo) .build(); // 存入请求上下文 requestContext.setProperty(SecurityIdentity.class.getName(), identity); } }
如果你使用的是Quarkus 2.x及更早版本,将所有jakarta包导入替换为javax即可
4. 业务层获取用户信息
你可以在任意Bean中直接注入SecurityIdentity获取认证后的用户信息:
import io.quarkus.security.identity.SecurityIdentity; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.annotation.security.RolesAllowed; @Path("/user") public class UserController { @Inject SecurityIdentity securityIdentity; @GET @Path("/current") // 角色校验注解直接生效,只要之前构造Identity时正确传入了roles @RolesAllowed("user") public UserInfo getCurrentUser() { return securityIdentity.getAttribute("fullUserInfo"); } }
生产环境配置注意
- 必须在Kong层配置拦截并丢弃客户端主动携带的
x-userinfo头,仅保留Kong OIDC插件生成的头,避免攻击者伪造身份 - 建议配置Quarkus仅监听内网地址,避免服务直接暴露到公网被绕过Kong访问
内容的提问来源于stack exchange,提问作者Trevor
相关产品推荐
相关产品推荐

