web-dev-qa-db-ja.com

スプリングレストテンプレートを使用してHTTPヘッダー(JWTトークン)をサービスに伝播する

私はマイクロサービスアーキテクチャを使用しており、どちらも春のセキュリティJWTトークンによってセキュリティ保護されています。

そのため、最初のマイクロサービスを呼び出すときに、JWTトークンを取得し、それらの資格情報を使用して別のサービスにリクエストを送信します。

トークンを取得して他のサービスに再送信するにはどうすればよいですか?

7
dragonalvaro

カスタムフィルターを作成するタスクを完了しました

public class RequestFilter implements Filter{



    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(RequestContext.REQUEST_HEADER_NAME);

        if (token == null || "".equals(token)) {
            throw new IllegalArgumentException("Can't retrieve JWT Token");
        }

        RequestContext.getContext().setToken(token);
        chain.doFilter(request, response);

    }

    @Override
    public void destroy() { }

    @Override
    public void init(FilterConfig arg0) throws ServletException {}


}

次に、私の設定で設定

    @Bean
public FilterRegistrationBean getPeticionFilter() {

    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new RequestFilter());
    registration.addUrlPatterns("/*");
    registration.setName("requestFilter");

    return registration;
}

これを念頭に置いて、ThreadLocal変数を使用して別のクラスを作成し、コントローラーからRest TemplaceインターセプターにJWTトークンを渡します

public class RequestContext {

public static final String REQUEST_HEADER_NAME = "Authorization";

private static final ThreadLocal<RequestContext> CONTEXT = new ThreadLocal<>();

private String token;

public static RequestContext getContext() {
    RequestContext result = CONTEXT.get();

    if (result == null) {
        result = new RequestContext();
        CONTEXT.set(result);
    }

    return result;
}

public String getToken() {
    return token;
}

public void setToken(String token) {
    this.token = token;
}

}

public class RestTemplateInterceptor implements ClientHttpRequestInterceptor{

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {

    String token = RequestContext.getContext().getToken();

    request.getHeaders().add(RequestContext.REQUEST_HEADER_NAME, token);

    return execution.execute(request, body);

}

}

インターセプターを構成に追加する

  @PostConstruct
public void addInterceptors() {
    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
    interceptors.add(new RestTemplateInterceptor());
    restTemplate.setInterceptors(interceptors);
}
8
dragonalvaro

基本的に、トークンはリクエストのヘッダーに配置する必要があります(例:Authorization:Bearer)。それを取得するには、コントローラーの@RequestHeader()で任意のヘッダー値を取得できます。

@GetMapping("/someMapping")
public String someMethod(@RequestHeader("Authorization") String token) {

}

これで、次のリクエストのヘッダー内にトークンを配置できます。

HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", token);

HttpEntity<RestRequest> entityReq = new HttpEntity<RestRequest>(request, headers);

これで、HttpEntityを残りのテンプレートに渡すことができます。

template.exchange("RestSvcUrl", HttpMethod.POST, entityReq, SomeResponse.class);

私が助けてくれることを願っています

10
paddy_89

次のように、RestTemplateに特別にインターセプターを追加することをお勧めします。

class RestTemplateHeaderModifierInterceptor(private val authenticationService: IAuthenticationService) : ClientHttpRequestInterceptor {
    override fun intercept(request: org.springframework.http.HttpRequest, body: ByteArray, execution: ClientHttpRequestExecution): ClientHttpResponse {
        if (!request.headers.containsKey("Authorization")) {
            // don't overwrite, just add if not there.
            val jwt = authenticationService.getCurrentUser()!!.jwt
            request.headers.add("Authorization", "Bearer $jwt")
        }
        val response = execution.execute(request, body)
        return response
    }
}

そして、次のようにRestTemplateに追加します。

@Bean
fun restTemplate(): RestTemplate {
    val restTemplate = RestTemplate()
restTemplate.interceptors.add(RestTemplateHeaderModifierInterceptor(authenticationService)) // add interceptor to send JWT along with requests.
    return restTemplate
}

そうすれば、RestTemplateが必要になるたびに、自動配線を使用して取得できます。次のように、TokenStoreからトークンを取得するには、AuthenticationServiceを実装する必要があります。


val details = SecurityContextHolder.getContext().authentication.details
if (details is OAuth2AuthenticationDetails) {
   val token = tokenStore.readAccessToken(details.tokenValue)
   return token.value
}

0
nickoooname