我有一个运行 EJB 应用程序的 Wildfly 服务器,如果我对应用程序进行 REST 客户端调用,EJB 安全上下文会自动填充有效的主体,我可以将其转换为 Keycloak 安全上下文并获取声明信息。 应用程序还接受 gRCP 调用,在这种情况下,安全上下文具有匿名主体,我想这是因为当 gRCP 调用传入时它尚未被填充。
我必须实现全局 gRPC 服务器拦截器吗?
有我可以遵循的例子吗?
这可能是因为 WildFly 中的 gRPC 和 Keycloak 之间没有自动集成,这与 REST 端点不同。
您需要实现一个全局 gRPC ServerInterceptor 来处理传入 gRPC 调用的身份验证和授权。
拦截器应该处理从 gRPC 元数据中提取和验证令牌。通常,此令牌是在 gRPC 调用中作为元数据标头传递的不记名令牌。
这是您的 ServerInterceptor 的基本轮廓:
import io.grpc.*;
import org.keycloak.adapters.jboss.KeycloakPrincipal;
import org.keycloak.representations.AccessToken;
public class KeycloakAuthInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
// Retrieve the Authorization header
String token = headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER));
if (token == null || !token.startsWith("Bearer ")) {
call.close(Status.UNAUTHENTICATED.withDescription("Authorization token missing"), headers);
return new ServerCall.Listener<ReqT>() {};
}
token = token.substring("Bearer ".length());
try {
// Verify token and populate security context
AccessToken accessToken = verifyTokenWithKeycloak(token);
if (accessToken == null) {
call.close(Status.UNAUTHENTICATED.withDescription("Invalid token"), headers);
return new ServerCall.Listener<ReqT>() {};
}
// Populate the security context (example uses WildFly's SecurityContext)
SecurityContext context = createSecurityContext(accessToken);
SecurityContextAssociation.setSecurityContext(context);
// Continue the gRPC call
return Contexts.interceptCall(Context.current(), call, headers, next);
} catch (Exception e) {
call.close(Status.UNAUTHENTICATED.withDescription("Failed to authenticate"), headers);
return new ServerCall.Listener<ReqT>() {};
}
}
private AccessToken verifyTokenWithKeycloak(String token) {
// Implement token verification with Keycloak here
return null; // Replace with actual token verification logic
}
private SecurityContext createSecurityContext(AccessToken accessToken) {
// Convert AccessToken to WildFly SecurityContext with KeycloakPrincipal
KeycloakPrincipal<?> principal = new KeycloakPrincipal<>("principal-name");
// Set up the security context and return it
return new SecurityContext(principal);
}
}