복붙노트

[SPRING] spring rest 템플릿을 사용하여 서비스에 HTTP 헤더 (JWT Token) 전파

SPRING

spring rest 템플릿을 사용하여 서비스에 HTTP 헤더 (JWT Token) 전파

나는 마이크로 서비스 아키텍처를 가지고 있는데, 둘 다 스프링 보안과 JWT 토큰으로 증권화했다.

그래서, 첫 번째 마이크로 서비스를 호출 할 때 JWT 토큰을 가져 와서 이러한 자격 증명을 사용하여 다른 서비스에 요청을 보내려합니다.

어떻게 토큰을 검색하고 다른 서비스로 다시 보낼 수 있습니까?

해결법

  1. ==============================

    1.기본적으로 토큰은 요청의 헤더에 있어야합니다 (예 : Authorization : Bearer). 그것을 얻으려면 컨트롤러에서 @RequestHeader ()를 통해 모든 헤더 값을 검색 할 수 있습니다.

    기본적으로 토큰은 요청의 헤더에 있어야합니다 (예 : 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);
    

    희망을 도울 수 있기를 바랍니다.

  2. ==============================

    2.필자는 작업을 완료하여 사용자 정의 필터를 작성했습니다.

    필자는 작업을 완료하여 사용자 정의 필터를 작성했습니다.

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

    이를 염두에두고, 컨트롤러에서 Rest Templace 인터셉터로 JWT 토큰을 전달하는 ThreadLocal 변수를 가진 다른 클래스를 작성했습니다.

    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);
    }
    
  3. ==============================

    3.나는 RestTemplate에 인터셉터를 특별히 추가하는 것이 더 좋다고 생각한다.

    나는 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
    }
    
    
  4. from https://stackoverflow.com/questions/46729203/propagate-http-header-jwt-token-over-services-using-spring-rest-template by cc-by-sa and MIT license