Spring Boot如何将REST控制器接收的Basic Auth凭证中继给RestTemplate
实现Basic Auth凭证从前端请求透传给RestTemplate的方案
实现该需求的核心逻辑是:用户请求ServiceA时,请求头的Authorization字段已携带完整的Basic Auth凭证,直接将该请求头透传到RestTemplate发往ServiceB的请求中即可,以下是两种常用实现方式:
方案1:全局RestTemplate拦截器(推荐,一次配置全量生效)
无需修改业务代码,配置后所有RestTemplate发起的调用都会自动透传当前请求的Basic Auth凭证:
- 第一步:自定义请求拦截器,实现
ClientHttpRequestInterceptor接口
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class BasicAuthForwardInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest currentRequest = attributes.getRequest(); String authHeader = currentRequest.getHeader(HttpHeaders.AUTHORIZATION); // 仅透传Basic类型的认证头,避免其他认证信息被误传 if (authHeader != null && authHeader.startsWith("Basic ")) { request.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); } } return execution.execute(request, body); } }
- 第二步:将拦截器注册到RestTemplate实例中
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; import java.util.Collections; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); ClientHttpRequestInterceptor authInterceptor = new BasicAuthForwardInterceptor(); restTemplate.setInterceptors(Collections.singletonList(authInterceptor)); return restTemplate; } }
提示:如果使用Spring Boot 3+版本,需要把代码中所有
javax.servlet相关的导入替换为jakarta.servlet。该方案仅在web请求上下文生效,异步线程、定时任务等无web上下文的场景调用不会透传凭证,也不会抛出异常。
方案2:手动透传凭证(适合仅少数接口需要透传的场景)
只需要在对应业务代码中手动获取请求头并塞入RestTemplate调用参数即可:
import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; @RestController public class TestController { private final RestTemplate restTemplate; public TestController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @GetMapping("/call-service-b") public String callServiceB() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpHeaders headers = new HttpHeaders(); if (attributes != null) { HttpServletRequest currentRequest = attributes.getRequest(); String authHeader = currentRequest.getHeader(HttpHeaders.AUTHORIZATION); if (authHeader != null && authHeader.startsWith("Basic ")) { headers.add(HttpHeaders.AUTHORIZATION, authHeader); } } HttpEntity<Void> requestEntity = new HttpEntity<>(headers); return restTemplate.postForObject("http://serviceB地址/目标接口路径", requestEntity, String.class); } }
内容的提问来源于stack exchange,提问作者ahelix
相关产品推荐
相关产品推荐

