Quarkus OIDC 安全链路时序图
- 请求进入
- OIDC 验证
SecurityIdentityAugmentor
ContainerRequestFilter
- Resource 方法
ContainerResponseFilter
- 响应返回
🖼️ 时序图(文字版)
┌─────────────────────────────┐
│ HTTP 请求 │
└──────────────┬──────────────┘│▼┌───────────────────┐│ OIDC 验证 (token) ││ 构建 SecurityIdentity │└─────────┬─────────┘│▼┌───────────────────────────────┐│ SecurityIdentityAugmentor ││ (增强身份 / 单点登录检查等) │└─────────────┬─────────────────┘│▼┌───────────────────────────────┐│ ContainerRequestFilter ││ (请求级拦截,能拿到identity)│└─────────────┬─────────────────┘│▼┌───────────────────┐│ Resource 方法调用 │└─────────┬─────────┘│▼┌───────────────────────────────┐│ ContainerResponseFilter ││ (统一返回值/异常包装) │└─────────────┬─────────────────┘│▼
┌─────────────────────────────┐
│ HTTP 响应 │
└─────────────────────────────┘
1️⃣ Demo 项目结构
最小可运行的 Quarkus Demo,包含以下三个类:
SecurityIdentityAugmentor
→ 增强身份,打印日志。ContainerRequestFilter
→ 请求级别过滤器,打印日志。ContainerResponseFilter
→ 响应级别过滤器,打印日志。
这样你启动应用、访问一个 REST 接口,就能看到日志执行顺序。
src└── main└── java└── com.example.demo├── LoggingIdentityAugmentor.java├── LoggingRequestFilter.java├── LoggingResponseFilter.java└── HelloResource.java
2️⃣ 代码示例
2.1 SecurityIdentityAugmentor
package com.example.demo;import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
import io.quarkus.security.identity.request.SecurityIdentityAugmentorRequest;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;@ApplicationScoped
public class LoggingIdentityAugmentor implements SecurityIdentityAugmentor {@Overridepublic CompletionStage<SecurityIdentity> augment(SecurityIdentity identity,SecurityIdentityAugmentorRequest request) {System.out.println(">>> [Augmentor] SecurityIdentityAugmentor executed, user = "+ identity.getPrincipal().getName());return CompletableFuture.completedFuture(identity);}
}
2.2 ContainerRequestFilter
package com.example.demo;import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.ext.Provider;@Provider
@Priority(Priorities.AUTHENTICATION + 10) // 在认证之后执行
public class LoggingRequestFilter implements ContainerRequestFilter {@InjectSecurityIdentity identity;@Overridepublic void filter(ContainerRequestContext requestContext) {System.out.println(">>> [RequestFilter] Executed for path = " + requestContext.getUriInfo().getPath()+ ", user = " + identity.getPrincipal().getName());}
}
2.3 ContainerResponseFilter
package com.example.demo;import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.ext.Provider;
import java.io.IOException;@Provider
public class LoggingResponseFilter implements ContainerResponseFilter {@Overridepublic void filter(ContainerRequestContext requestContext,ContainerResponseContext responseContext) throws IOException {System.out.println(">>> [ResponseFilter] Executed, status = " + responseContext.getStatus());}
}
2.4 REST Resource
package com.example.demo;import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;@Path("/hello")
public class HelloResource {@GETpublic Response hello() {System.out.println(">>> [Resource] Hello endpoint executed");return Response.ok("Hello from Quarkus!").build();}
}
3️⃣ 运行效果
启动应用后,访问:
curl http://localhost:8080/hello
日志输出顺序应当是:
>>> [Augmentor] SecurityIdentityAugmentor executed, user = <user>
>>> [RequestFilter] Executed for path = hello, user = <user>
>>> [Resource] Hello endpoint executed
>>> [ResponseFilter] Executed, status = 200
这样,你就能清楚看到 Augmentor → RequestFilter → Resource → ResponseFilter 的调用顺序。
✅ 总结
SecurityIdentityAugmentor
→ 在 认证阶段(构建SecurityIdentity
时执行),比ContainerRequestFilter
更早。ContainerRequestFilter
→ 在 认证完成后、进入 Resource 前执行。ContainerResponseFilter
→ 在 Resource 方法执行完后,返回给客户端前执行。