如何将数据从gRPC拦截器传递给服务方法调用?

时间:2017-07-05 14:33:11

标签: java rpc grpc

我需要将ServerAuthIntereptor的一些数据传递给来电。

ServerAuthInterceptor:

// used in context parameters map
private static final String AUTH_CONTEXT = "authContext";
private static final Context.Key<Object> AUTH_CONTEXT_KEY = Context.key(AUTH_CONTEXT);

// ...

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
    ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

    // check credentials from header

    // remember account and session token for usage later (eg. in logout)
    AuthContext authContext = new AuthContext();
    authContext.account = account;
    authContext.sessionToken = sessionToken;

    logger.info("Call {} allowed (account={}, authContext={})",
        new Object[] { call, account, authContext });

    Context context = Context
        .current()
        .withValue(AUTH_CONTEXT_KEY, authContext);

    return Contexts.interceptCall(context, call, headers, next);
}

// ...

/**
 * To be used from services
 * @return
 */
public static Account getCurrentContextAccount() {
    AuthContext authContext = (AuthContext) Context.current().key(AUTH_CONTEXT).get();
    return authContext.account;
}

在某些服务方法实现中,我尝试从当前上下文访问存储的“authContext”:

@Override
public void list(ListRequest request, StreamObserver<ListResponse> responseObserver) {
    logger.info("Starting list({}) ...", request);

     // ...

     account = ServerAuthInterceptor.getCurrentContextAccount();

但是authContext是null。 它有时工作,所以我相信它与线程(本地人)有关。

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

由于某些原因它不起作用AuthContext类,但如果我分别传递2个上下文值,它就有效:

ServerAuthInterceptor:

Context context = Context
        .current()
        .withValue(AUTH_TOKEN_KEY, sessionToken)
        .withValue(AUTH_ACCOUNT_KEY, account);

服务电话:

/**
 * To be used from services
 * @return
 */
public static Account getCurrentContextAccount() {
    return (Account) AUTH_ACCOUNT_KEY.get();
}

/**
 * To be used from services
 * @return
 */
public static String getCurrentContextSessionToken() {
    return (String) AUTH_TOKEN_KEY.get();
}

答案 1 :(得分:1)

上下文密钥使用引用相等性。因此,您必须使用相同的密钥实例进行设置和获取。

此代码重新创建了密钥,因此它不匹配:

Context.current().key(AUTH_CONTEXT).get();

相反应该是:

AUTH_CONTEXT_KEY.get();

使用引用相等性,因此您可以将正常Java可见性(公共,受保护,包私有,私有)规则应用于值,就像使用ThreadLocal一样。