How to pass data from gRPC interceptor to service method call?

主宰稳场 提交于 2019-12-13 17:05:23

问题


I need to pass some data from my ServerAuthIntereptor to call.

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;
}

In some service method implementation i try to access that stored 'authContext' from current context:

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

     // ...

     account = ServerAuthInterceptor.getCurrentContextAccount();

But authContext is null. It's working sometimes so i believe it's related to threads(locals).

What is proper way to do it?


回答1:


For some reason it does not work fot AuthContext class, but it works if i pass 2 context values separately:

ServerAuthInterceptor:

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

Service call:

/**
 * 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();
}



回答2:


Context Keys use reference equality. Thus, you must use the same key instance for setting and getting.

This code re-created the key, so it wouldn't match:

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

Instead it should have been:

AUTH_CONTEXT_KEY.get();

Reference equality is used so you can apply normal Java visibility (public, protected, package-private, private) rules to the value, as you can do with ThreadLocal.



来源:https://stackoverflow.com/questions/44929156/how-to-pass-data-from-grpc-interceptor-to-service-method-call

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!