如何在java spring boot中从请求的标头中获取持有者令牌?

嗨,试图实现的是获取从java spring boot RESTApi控制器中的前端提交的持有者令牌,并使用假装客户端向另一个微服务执行另一个请求?这是我所做的

enter image description here

上面的图片是我如何从邮递员那里做我的请求,这是我的控制器代码:

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

这是我的服务的样子:

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

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


答案 1

尽管建议的答案有效,但每次将令牌传递给调用仍然不是执行此操作的最佳方法。我建议为假装请求创建一个拦截器,在那里你可以从中提取令牌并直接将其添加到请求标头中。喜欢这个:FeignClientRequestContextHolder

    @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());
       
      }
    }

这样,您就可以为您的问题找到一个干净的解决方案


答案 2

您在这里有几种选择。

例如,您可以使用一个请求范围的 Bean,也可以按照您的建议使用一个 MVC 拦截器

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

public class BearerTokenWrapper {
   private String token;

   // setters and getters
}

然后,提供 MVC 处理程序接收器的实现:

public class BearerTokenInterceptor extends HandlerInterceptorAdapter {

  private BearerTokenWrapper tokenWrapper;

  public BearerTokenInterceptor(BearerTokenWrapper tokenWrapper) {
    this.tokenWrapper = tokenWrapper;
  }

  @Override
  public boolean preHandle(HttpServletRequest request,
          HttpServletResponse response, Object handler) throws Exception {
    final String authorizationHeaderValue = request.getHeader("Authorization");
    if (authorizationHeaderValue != null && authorizationHeaderValue.startsWith("Bearer")) {
      String token = authorizationHeaderValue.substring(7, authorizationHeaderValue.length());
      tokenWrapper.setToken(token);
    }
    
    return true;
  }
}

此侦听器应在 MVC 配置中注册。例如:

@EnableWebMvc
@Configuration
public class WebConfiguration extends WebConfigurer { /* or WebMvcConfigurerAdapter for Spring 4 */

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(bearerTokenInterceptor());
  }

  @Bean
  public BearerTokenInterceptor bearerTokenInterceptor() {
      return new BearerTokenInterceptor(bearerTokenWrapper());
  }

  @Bean
  @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public BearerTokenWrapper bearerTokenWrapper() {
    return new BearerTokenWrapper();
  }

}

通过此设置,您可以在自动布线相应的 Bean 时使用 Bean:Service

@Autowired
private BearerTokenWrapper tokenWrapper;

//...


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

}

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

    String tokenString = tokenWrapper.getToken();
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData("Bearer " + tokenString, ids);
    
    return () -> partnerDtoResponse;
}

此处在堆栈溢出中也提供了类似的解决方案。例如,请参阅此相关问题

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

老实说,我从未测试过它,但似乎您可以在Feiign客户端定义中提供请求标头值,在您的情况下,如下所示:

@FeignClient(name="AccountFeignClient")
public interface AccountFeignClient {    
    @RequestMapping(method = RequestMethod.GET, value = "/data")
    List<PartnerDto> getData(@RequestHeader("Authorization") String token, Set<Long> ids);
}

当然,你也可以一个常见的,其他的可以扩展。这将提供从标头和提供的HTTP请求中获取持有者令牌所需的逻辑,但在我看来,上述任何解决方案都更好。ControllerControllerControllerAuthorization


推荐