Wildfly:Keycloak oAuth 令牌的 gRPC 服务器拦截器

问题描述 投票:0回答:1

我有一个运行 EJB 应用程序的 Wildfly 服务器,如果我对应用程序进行 REST 客户端调用,EJB 安全上下文会自动填充有效的主体,我可以将其转换为 Keycloak 安全上下文并获取声明信息。 应用程序还接受 gRCP 调用,在这种情况下,安全上下文具有匿名主体,我想这是因为当 gRCP 调用传入时它尚未被填充。

我必须实现全局 gRPC 服务器拦截器吗?

有我可以遵循的例子吗?

keycloak ejb wildfly
1个回答
0
投票

这可能是因为 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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.