Best way to propagate credentials between micro services using spring-session

£可爱£侵袭症+ 提交于 2019-12-07 08:45:49

问题


We are using an architecture very similar to the one described in this great guide on spring.io. Our gateway handles authentication, and sessions are stored in Redis using spring-session. Endpoints of our micro services are secured and also use spring-session.

In a micro service I need to call an endpoint of another micro service. I get the URL easily through the discovery client, but I need to provide credentials and I'm not sure of the best way to achieve that.

I am thinking about getting the SESSION cookie from the HttpRequest, store it in some kind of thread local variables or request scope bean, and use it in the RestTemplate to call the second micro service. I need this request scoped bean because the RestTemplate will be used in the service layer, i.e. not in the MVC controller, and I don't want to pollute my service layer methods with this session identifier I get from the cookie.

Is there a better way to approach this need? Is there already some support in Spring Cloud for this?

Thanks a lot for your input


回答1:


At this time the easiest way to access the Spring Session id is using RequestContextHolder.getRequestAttributes().getId(). Once you have access to that you can write a custom ClientHttpRequestInterceptor to include the session id in requests:

public SpringSessionClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        boolean isMyService = ...;

        // very important not to send the session id to external services
        if(isMyService) {
            request.getHeaders().add("x-auth-token", RequestContextHolder.getRequestAttributes().getId());
        }
    }
}

Then when you create your RestTemplate make sure to add SpringSessionClientHttpRequestInterceptor.

RestTemplate rest = new RestTemplate();
rest.getInterceptors().add(new SpringSessionClientHttpRequestInterceptor());



回答2:


I had a similar scenario where I also needed to pass the CSRF token in the RestTemplate. I know you don't want to implement it in the controller but maybe it will give some additional insight (as this question helped me solve the issue). Here is how I implemented it in my controller:

@RequestMapping(value = "/assets/download", method = RequestMethod.POST, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> downloadAssets(HttpSession session, @RequestBody SelectedAssets selectedAssets){
    ...
    ...

    CsrfToken token = (CsrfToken) session.getAttribute("org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN");  

    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.set("Cookie", "SESSION=" + session.getId() + "; XSRF-TOKEN=" + token.getToken());
    headers.set("X-XSRF-TOKEN", token.getToken());
    HttpEntity<SelectedAssets> selectedAssetsEntity = new HttpEntity<>(selectedAssets, headers);
    ResponseEntity<JobResponse> jobResponseResponseEntity = restTemplate.postForEntity("http://localhost:8102/jobs/package", selectedAssetsEntity, JobResponse.class);

    ...
    ...
}


来源:https://stackoverflow.com/questions/31875205/best-way-to-propagate-credentials-between-micro-services-using-spring-session

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!