java 使用 spring 休息模板在服务上传播 HTTP 标头(JWT 令牌)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46729203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:20:20  来源:igfitidea点击:

Propagate HTTP header (JWT Token) over services using spring rest template

javaspringrestjwt

提问by dragonalvaro

I have a microservice architecture, both of them securized by spring security an JWT tokens.

我有一个微服务架构,它们都由 Spring Security 和 JWT 令牌保护。

So, when I call my first microservice, I want to take the JWT token and send a request to another service using those credentials.

因此,当我调用我的第一个微服务时,我想获取 JWT 令牌并使用这些凭据向另一个服务发送请求。

How can I retrieve the token and sent again to the other service?

如何检索令牌并再次发送到其他服务?

回答by paddy_89

Basically your token should be located in the header of the request, like for example: Authorization: Bearer . For getting it you can retrieve any header value by @RequestHeader() in your controller:

基本上,您的令牌应位于请求的标头中,例如: Authorization: Bearer 。要获取它,您可以通过控制器中的 @RequestHeader() 检索任何标头值:

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

}

Now you can place the token within the header for the following request:

现在,您可以将令牌放在以下请求的标头中:

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

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

Now you can pass the HttpEntity to your rest template:

现在您可以将 HttpEntity 传递给您的休息模板:

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

Hope I could help

希望我能帮上忙

回答by dragonalvaro

I've accomplished the task, creating a custom Filter

我已经完成了任务,创建了一个自定义过滤器

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


}

Then, setting in my config

然后,在我的配置中设置

    @Bean
public FilterRegistrationBean getPeticionFilter() {

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

    return registration;
}

With that in mind, I've create another class with a ThreadLocal variable to pass the JWT token from the Controller to the Rest Templace interceptor

考虑到这一点,我创建了另一个带有 ThreadLocal 变量的类,以将 JWT 令牌从控制器传递到 Rest Tempplace 拦截器

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

}

}

Add interceptor to the config

在配置中添加拦截器

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

回答by nickoooname

I think it is better to add the interceptor specifically to the RestTemplate, like this:

我认为最好将拦截器专门添加到 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
    }
}

And add it to the RestTemplate like so:

并将其添加到 RestTemplate 中,如下所示:

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

That way, every time you need a RestTemplate you can just use autowiring to get it. You do need to implement the AuthenticationService still to get the token from the TokenStore, like this:

这样,每次您需要 RestTemplate 时,您都可以使用自动装配来获取它。您仍然需要实现 AuthenticationService 以从 TokenStore 获取令牌,如下所示:


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