gRPC Java — хранение переменных состояния (для аутентификации пользователя)

Я использую gRPC в среде SpringBoot (и SpringSecurity) и использую ServerInterceptor для аутентификации пользователей при их подключении. Я сохраняю результат аутентификации в Spring SecurityContextHolder. (Подписался)

private final AuthenticationManager manager;

@Autowired
public AuthenticatorInterceptor(final AuthenticationManager manager) {
    this.manager = manager;
}

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
                                                             Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
    logger.info("Authorizing user information for GRPC access");

    final String authHeader = nullToEmpty(metadata.get(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER)));
    if (!authHeader.startsWith("Basic ")) {
        logger.error("No Authentication Info found");
        throw Status.PERMISSION_DENIED.withDescription("No Authentication Info found").asRuntimeException();
    }

    try {
        final String[] tokens = decodeBasicAuth(authHeader);
        final String userName = tokens[0];

        if (authenticationIsRequired(userName)) {
            final Authentication pending = new UsernamePasswordAuthenticationToken(userName, tokens[1]);
            final Authentication result = manager.authenticate(pending);
            logger.info("Authentication success for this user");

            SecurityContextHolder.getContext().setAuthentication(result);
        }
    } catch (AuthenticationException e) {
        SecurityContextHolder.clearContext();
        logger.error("Authentication failed - No GRPC Access", e);
        throw Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e).asRuntimeException();
    }

    return serverCallHandler.startCall(serverCall, metadata);
}

Но проблема в том, что аутентификация просачивается и распределяется между клиентами. Например, если клиент А подключается и аутентифицируется, а затем, когда подключается другой клиент Б, клиент Б уже аутентифицирован с учетными данными клиента А.

Я предполагаю, что это связано с тем, что по умолчанию SecurityContext из SecurityContextHolder использует ThreadLocal для хранения информации аутентификации, а gRPC, вероятно, повторно использует потоки для разных соединений.

Где хранить информацию для аутентификации? Я видел класс Context (контекст gRPC), но не мог понять (и не мог найти никакого ресурса), как правильно реализовать требуемую мне функциональность.

PS: для настройки сервера gRPC и его перехватчики.


person Sudara    schedule 18.06.2018    source источник
comment
Взгляните на stackoverflow.com/a/40113309/4690866.   -  person Eric Anderson    schedule 18.06.2018