如何在JavaSpringBoot中从请求头中获取承载令牌?

如何在JavaSpringBoot中从请求头中获取承载令牌?,java,spring-boot,bearer-token,spring-cloud-feign,Java,Spring Boot,Bearer Token,Spring Cloud Feign,您好,尝试实现的是在JavaSpringBootRestaPI控制器中获取前端提交的承载令牌,并使用假客户端向另一个微服务执行另一个请求?我就是这么做的 上图是我如何向邮递员提出请求的,以下是我的控制器代码: @Operation(summary = "Save new") @PostMapping("/store") public ResponseEntity<ResponseRequest<TransDeliveryPlanning>

您好,尝试实现的是在JavaSpringBootRestaPI控制器中获取前端提交的承载令牌,并使用假客户端向另一个微服务执行另一个请求?我就是这么做的

上图是我如何向邮递员提出请求的,以下是我的控制器代码:

@Operation(summary = "Save new")
@PostMapping("/store")
public ResponseEntity<ResponseRequest<TransDeliveryPlanning>> saveNewTransDeliveryPlanning(
        @Valid @RequestBody InputRequest<TransDeliveryPlanningDto> request) {

    TransDeliveryPlanning newTransDeliveryPlanning = transDeliveryPlanningService.save(request);

    ResponseRequest<TransDeliveryPlanning> response = new ResponseRequest<TransDeliveryPlanning>();

    if (newTransDeliveryPlanning != null) {
        response.setMessage(PESAN_SIMPAN_BERHASIL);
        response.setData(newTransDeliveryPlanning);
    } else {
        response.setMessage(PESAN_SIMPAN_GAGAL);
    }

    return ResponseEntity.ok(response);
}
@操作(summary=“Save new”)
@后映射(“/存储”)
公共响应节约新的运输计划(
@有效@RequestBody输入请求){
TransDeliveryPlanning newTransDeliveryPlanning=transDeliveryPlanningService.save(请求);
ResponseRequest response=新的ResponseRequest();
if(newTransferryPlanning!=null){
回复:setMessage(PESAN_SIMPAN_BERHASIL);
响应.setData(新TransferryPlanning);
}否则{
回复:setMessage(PESAN_SIMPAN_GAGAL);
}
返回ResponseEntity.ok(响应);
}
我的服务是这样的:

public TransDeliveryPlanning save(InputRequest<TransDeliveryPlanningDto> request) {
       Future<List<PartnerDto>> initPartners = execs.submit(getDataFromAccount(transDeliveryPlanningDtSoDtoPartnerIdsSets));

}

public Callable<List<PartnerDto>> getDataFromAccount(Set<Long> ids) {

    String tokenString = "i should get the token from postman, how do i get it to here?";
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData("Bearer " + tokenString, ids);
    
    return () -> partnerDtoResponse;
}
公共TransDeliveryPlanning保存(输入请求){
Future initPartners=execs.submit(getdatafromcount(transDeliveryPlanningDtSoDtoPartnerIdsSets));
}
公共可调用getDataFromAccount(设置ID){
String tokenString=“我应该从邮递员那里拿到代币,怎么才能拿到这里?”;
List partnerDtoResponse=accountFeignClient.getData(“承载者”+令牌字符串,ID);
return()->partnerDtoResponse;
}

正如你所看到的,在“tokenString”中,我放了一个我质疑的字符串,我如何从邮递员那里得到它?

我得到了答案,但我认为我仍将等待更好的选择,因为我在这里的答案是,我必须在每个控制器中添加@RequestHeader来获取令牌的值,并使用
String token=headers.getFirst(HttpHeaders.AUTHORIZATION)获取令牌,这是我的完整控制器:

@Operation(summary = "Save new")
@PostMapping("/store")
public ResponseEntity<ResponseRequest<TransDeliveryPlanning>> saveNewTransDeliveryPlanning(@RequestHeader HttpHeaders headers, 
        @Valid @RequestBody InputRequest<TransDeliveryPlanningDto> request) {

    String token = headers.getFirst(HttpHeaders.AUTHORIZATION);

    TransDeliveryPlanning newTransDeliveryPlanning = transDeliveryPlanningService.save(token, request);

    ResponseRequest<TransDeliveryPlanning> response = new ResponseRequest<TransDeliveryPlanning>();

    if (newTransDeliveryPlanning != null) {
        response.setMessage(PESAN_SIMPAN_BERHASIL);
        response.setData(newTransDeliveryPlanning);
    } else {
        response.setMessage(PESAN_SIMPAN_GAGAL);
    }

    return ResponseEntity.ok(response);
}
@操作(summary=“Save new”)
@后映射(“/存储”)
公共响应属性SaveNewTransferryPlanning(@RequestHeader HttpHeaders,
@有效@RequestBody输入请求){
字符串标记=headers.getFirst(HttpHeaders.AUTHORIZATION);
TransDeliveryPlanning newTransDeliveryPlanning=transDeliveryPlanningService.save(令牌,请求);
ResponseRequest response=新的ResponseRequest();
if(newTransferryPlanning!=null){
回复:setMessage(PESAN_SIMPAN_BERHASIL);
响应.setData(新TransferryPlanning);
}否则{
回复:setMessage(PESAN_SIMPAN_GAGAL);
}
返回ResponseEntity.ok(响应);
}

我在某个地方读到一个叫做
拦截器的东西,所以我们不必在我认为的每个控制器中键入@RequestHeader,但我不知道这是否是解决方案,也不知道如何正确使用它。如果有人能做得更好,我会接受你的回答。

你有几个选择

例如,您可以使用和,正如您所建议的,一

基本上,您需要为令牌值定义一个包装器:

public类BearerTokenWrapper{
私有字符串令牌;
//二传手和接球手
}
然后,提供一个MVC的实现:

公共类BealerTokenInterceptor扩展HandlerInterceptor适配器{
私人承载器tokenWrapper tokenWrapper;
公共BearTokenReceptor(BearTokenRapper tokenWrapper){
this.tokenWrapper=tokenWrapper;
}
@凌驾
公共布尔预处理(HttpServletRequest,
HttpServletResponse,对象处理程序)引发异常{
最终字符串authorizationHeaderValue=request.getHeader(“授权”);
if(authorizationHeaderValue!=null&&authorizationHeaderValue.startsWith(“承载人”)){
字符串标记=authorizationHeaderValue.substring(7,authorizationHeaderValue.length());
tokenWrapper.setToken(令牌);
}
返回true;
}
}
这个拦截器应该在MVC配置中注册。例如:

@EnableWebMvc
@配置
公共类WebConfiguration扩展了Spring 4的WebConfigure{/*或WebMVCConfigureAdapter*/
@凌驾
公共无效附加接收器(侦听器注册表){
addInterceptor(bearertokeinterceptor());
}
@豆子
公共承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器承载器(){
返回新的bearertokenreceptor(bearerTokenWrapper());
}
@豆子
@作用域(value=WebApplicationContext.Scope\u请求,proxyMode=ScopedProxyMode.TARGET\u类)
公共广播电台广播电台广播电台广播电台广播电台广播电台{
返回新的bearerTokenRapper();
}
}
通过此设置,您可以在
服务中使用bean
自动连接相应的bean:

@Autowired
私人承载器tokenWrapper tokenWrapper;
//...
公共TransDeliveryPlanning保存(输入请求){
Future initPartners=execs.submit(getdatafromcount(transDeliveryPlanningDtSoDtoPartnerIdsSets));
}
公共可调用getDataFromAccount(设置ID){
String tokenString=tokenWrapper.getToken();
List partnerDtoResponse=accountFeignClient.getData(“承载者”+令牌字符串,ID);
return()->partnerDtoResponse;
}
在堆栈溢出中也提供了类似的解决方案。例如,请参见

除了这种基于Spring的方法之外,您还可以尝试类似于中公开的解决方案的方法

老实说,我从未测试过它,但您似乎可以在外部客户机定义中提供请求头值,在您的情况下,类似于:

@FeignClient(name=“AccountFeignClient”)
公共接口AccountFaignClient{
@RequestMapping(method=RequestMethod.GET,value=“/data”)
List getData(@RequestHeader(“授权”)字符串令牌,设置ID);
}
当然,您也可以使用其他
控制器可以扩展的通用
控制器。该
控制器将提供从
授权获取承载令牌所需的逻辑<
package com.north.config;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class DefaultApiFilter implements Filter {


@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) servletRequest;

    String auth = req.getHeader("Authorization");

    //TODO if you want you can persist your token here and use it on other place

    //TODO This may be used for verification if it comes from the right endpoint and if you should save the token
    final String requestURI = ((RequestFacade) servletRequest).getRequestURI();

    filterChain.doFilter(servletRequest, servletResponse);
    }
}
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class BearerTokenUtil {

  public static String getBearerTokenHeader() {
    return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("Authorization");
  }
}
public TransDeliveryPlanning save(InputRequest<TransDeliveryPlanningDto> request) {
       Future<List<PartnerDto>> initPartners = execs.submit(getDataFromAccount(transDeliveryPlanningDtSoDtoPartnerIdsSets));
}

public Callable<List<PartnerDto>> getDataFromAccount(Set<Long> ids) {
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData(BearerTokenUtil.getBearerTokenHeader(), ids);
    return () -> partnerDtoResponse;
}
    @Component
    public class FeignClientInterceptor implements RequestInterceptor {
    
      private static final String AUTHORIZATION_HEADER = "Authorization";

      public static String getBearerTokenHeader() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("Authorization");
      }
    
      @Override
      public void apply(RequestTemplate requestTemplate) {

          requestTemplate.header(AUTHORIZATION_HEADER, getBearerTokenHeader());
       
      }
    }
@Configuration
@EnableFeignClients(
    defaultConfiguration = DefaultFeignConfiguration.class
)
public class FeignConfig
{
}
@Configuration
@Import(FeignClientsConfiguration.class)
public class DefaultFeignConfiguration
{
    @Bean
    public RequestInterceptor userAgentHeaderInterceptor() {
        return UserAgentHeaderInterceptor();
    } 
}
public class UserAgentHeaderInterceptor extends BaseHeaderInterceptor
{

    private static final String USER_AGENT = "User-Agent";


    public UserAgentHeaderInterceptor()
    {
        super(USER_AGENT);
    }
}
public class BaseHeaderInterceptor implements RequestInterceptor
{

    private final String[] headerNames;


    public BaseHeaderInterceptor(String... headerNames)
    {
        this.headerNames = headerNames;
    }


    @Override
    public void apply(RequestTemplate template)
    {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        if (attributes != null)
        {
            HttpServletRequest httpServletRequest = attributes.getRequest();

            for (String headerName : headerNames)
            {
                String headerValue = httpServletRequest.getHeader(headerName);
                if (headerValue != null && !headerValue.isEmpty())
                {
                    template.header(headerName, headerValue);
                }
            }
        }
    }
}