1

Я экспериментирую с gRPC с использованием «backend» и Android «front-end» на основе Spring, идея заключается в том, что я попрошу токен доступа с использованием типа предоставления пароля через HTTP (используя стандартную конечную точку RESTful/oauth/token) и использовать токен доступа, предоставляемый во всех последующих запросах через RPC (установка заголовка авторизации).gRPC и OAuth2 Аутентификация с весной Безопасность

У меня есть серверный перехватчик gRPC на моем «backend» моей пружины, который получит заголовок авторизации от вызова сервера и аутентифицирует токен доступа к хранилищу токенов.

Я застрял в том, что делать дальше или даже если то, что у меня есть до сих пор, является «правильным» подходом.

Это мой перехватчик:

@Component 
public class GrpcRequestInterceptor implements ServerInterceptor { 
private AuthenticationManager authenticationManager; 

public GrpcRequestInterceptor(AuthenticationManager authenticationManager, AuthorizationCodeServices authorizationCodeServices) { 
     this.authenticationManager = authenticationManager; 
} 

@Override 
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) { 
     String authorizationHeader = metadata.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)); 

     PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = 
       new PreAuthenticatedAuthenticationToken(authorizationHeader.substring("Bearer ".length()), ""); 

     PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider(); 
     preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(new AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken>() { 
      @Override 
      public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken) throws UsernameNotFoundException { 
       ???? 
      } 
     }); 
     Authentication authentication = preAuthenticatedAuthenticationProvider.authenticate(preAuthenticatedAuthenticationToken); 

     SecurityContextHolder.getContext().setAuthentication(authentication); 

     return serverCallHandler.startCall(serverCall, metadata); 
    } 
} 

Как получить маркер службы и как проверить подлинность моего пользователя от этой службы, используя только маркер доступа я обеспечиваю себя.

Моя конфигурация безопасности выглядит следующим образом:

@Configuration 
@EnableAuthorizationServer 
@EnableResourceServer 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Autowired 
    private AccountDetailsService accountDetailsService; 

    @Profile(value = "development") 
    @Override 
    public void configure(WebSecurity web) throws Exception { 
     web.ignoring().antMatchers("/h2-console/**"); 
    } 

    @Override 
    public void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(accountDetailsService) 
       .passwordEncoder(initPasswordEncoder()); 
    } 

    @Bean 
    public PasswordEncoder initPasswordEncoder() { 
     return new BCryptPasswordEncoder(10); 
    } 
} 

Должен ли я быть установкой службы маркеров вручную здесь, а затем инъекционной, что в мой перехватчик или ??? Что такое «самый веский» способ добиться этого?

Любая помощь очень ценится!

ответ

1

Возможно, у вас есть компонент org.springframework.security.oauth2.provider.token.TokenStore, который вы можете ввести, чтобы получить аутентификацию. Затем вы можете сделать что-то вдоль линии

@Autowired 
private TokenStore tokenstore; 

... 

Authentication authentication = this.tokenstore.readAuthentication(authorizationHeader.substring("Bearer ".length())).getUserAuthentication(); 

(добавить необходимые проверки нуля).

+0

Точно, что я сделал в конце. Спасибо за ответ! – CurtisWebDev

1

Что я в итоге сделал, я был в курсе!

@Component 
public class GrpcRequestInterceptor implements ServerInterceptor { 
    @Autowired 
    private TokenStore tokenStore; 

    @Override 
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) { 
     boolean isAuthenticated = isAuthenticated(
      metadata.get(
        Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) 
      ).substring("Bearer ".length()) 
     ); 

     if (isAuthenticated) { 
      return serverCallHandler.startCall(serverCall, metadata); 
     } 

     throw new UnauthorizedClientException("Unauthorised client connection."); 
    } 

    private boolean isAuthenticated(String bearerToken) { 
     OAuth2Authentication authentication = tokenStore.readAuthentication(bearerToken); 
     if (authentication == null) { 
      return false; 
     } 

     SecurityContextHolder.getContext().setAuthentication(authentication); 

     return true; 
    } 
} 
+0

Привет, CurtisWebDev, я начал работать над тем же точно реализующим OAuth2.0. Здесь мой пользовательский принцип приходит от самого сервера gRPC. поэтому я получаю исключение для пароля (так как это должен быть двоичный формат) при выборе пользователя. Хотя я реализую сервер interecptor, также я не получаю основной или токен. Не могли бы вы поделитесь мной больше кода через github или любым другим способом. Ваша помощь заставляет меня чувствовать себя лучше и ценить. Любые предложения приветствуются. – Basavaraj

1

Возможно, лучше использовать проводку в ResourceServerTokenServices вместо TokenStore. ResourceServerTokenServices будет выполнять дополнительные проверки токена доступа, который не работает TokenStore, например, чтобы токен не истек.

@Autowired 
private ResourceServerTokenServices tokenServices; 

... 

OAuth2Authentication authentication = tokenServices.loadAuthentication(token); 
SecurityContextHolder.getContext().setAuthentication(authentication); 
Смежные вопросы