如何从java spring boot中的请求头中获取承载令牌?

Ke *_*Vin 16 java spring-boot bearer-token spring-cloud-feign

嗨,试图实现的是获取从前端提交的承载令牌在 java spring boot RESTApi 控制器中,并使用伪装客户端向另一个微服务发出另一个请求?这是我所做的

在此处输入图片说明

上图是我如何处理邮递员的请求,这是我的控制器代码:

@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);
}
Run Code Online (Sandbox Code Playgroud)

这是我的服务的样子:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

sta*_*ker 13

尽管建议的答案有效,但每次将令牌传递给FeignClient调用仍然不是最好的方法。我建议为假请求创建一个拦截器,您可以从中提取令牌RequestContextHolder并将其直接添加到请求标头中。像这样:

    @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());
       
      }
    }
Run Code Online (Sandbox Code Playgroud)

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


Fon*_*ard 13

从标头获取Bearer Token 的一种简单方法是将@RequestHeader与标头名称一起使用。

请参阅下面的代码示例

@PostMapping("/some-endpoint")
public ResponseEntity<String> someClassNmae(@RequestHeader("Authorization") String bearerToken) {

   System.out.println(bearerToken); // print out bearer token

   // some more code
}
Run Code Online (Sandbox Code Playgroud)


jcc*_*ero 8

您在这里有多种选择。

例如,您可以使用请求范围的 bean,并且如您所建议的那样,使用一个MVC 拦截器

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

public class BearerTokenWrapper {
   private String token;

   // setters and getters
}
Run Code Online (Sandbox Code Playgroud)

然后,提供一个 MVC 的实现HandlerInterceptor

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这个拦截器应该在你的 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();
  }

}
Run Code Online (Sandbox Code Playgroud)

通过此设置,您可以在Service自动装配相应的 bean 中使用 bean:

@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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

老实说,我从未测试过它,但您似乎可以在 Feign 客户端定义中直接提供请求标头值,在您的情况下是这样的:

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

当然,你也可以Controller是其他Controllers可以扩展的common 。这Controller将提供从头Authorization和提供的 HTTP 请求中获取承载令牌所需的逻辑,但在我看来,上述任何解决方案都更好。