programing

Java Spring Boot 요청 헤더에서 베어러 토큰을 얻는 방법

cafebook 2023. 2. 22. 23:13
반응형

Java Spring Boot 요청 헤더에서 베어러 토큰을 얻는 방법

Hi, 달성하려고 하는 것은 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);
}

서비스 내용은 다음과 같습니다.

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"에 제가 질문했던 문자열을 넣었습니다, 우체부에서 어떻게 그곳으로 보낼 수 있을까요?

권장되는 답변은 기능하지만 매번 토큰을 에 전달합니다.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());
       
      }
    }

이렇게 하면 문제를 깔끔하게 해결할 수 있습니다.

여기에는 몇 가지 옵션이 있습니다.

예를 들어 요청 범위 지정 빈과 권장하는 대로 1개의 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();
  }

}

이 셋업으로 빈을 사용할 수 있습니다.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 기반 접근법에 더해 이 다른 스택오버플로우 질문에 나타난 솔루션과 유사한 방법을 시도해 볼 수 있습니다.

솔직히 테스트한 적은 없지만 다음과 같은 경우 Feign 클라이언트 정의에서 요청 헤더 값을 바로 제공할 수 있을 것 같습니다.

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

물론, 당신은 또한 공통으로Controller저 쪽Controller는 확장할 수 있습니다.이것.Controller로부터 베어러 토큰을 취득하기 위해 필요한 로직을 제공합니다.Authorization헤더와 HTTP 요청이 제공되었지만, 제 생각에는 앞서 언급한 솔루션 중 하나가 더 나은 것 같습니다.

헤더에서 베어러 토큰을 취득하는 간단한 방법은 @Request를 사용하는 것입니다.헤더 이름을 가진 헤더.

아래 코드 샘플 참조

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

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

   // some more code
}

저도 비슷한 경우가 있었어요.한 마이크로 서비스의 요청을 가로채고 토큰을 가져와 새 ApiClient를 설정하고 이 ApiClient를 사용하여 다른 마이크로 서비스에서 엔드포인트를 호출했습니다.하지만 클라이언트를 가장해서 미리 설정할 수 있는 가능성은 정말 없습니다.DefaultApiFilter를 생성하여 요구를 대행 수신하고 토큰을 데이터베이스에 저장한 후(또는 정적 변수, 싱글톤클래스 등으로 설정), FeignClient를 사용할 때 서비스 메서드를 호출합니다.

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

★★★★★★★★★★★★★★★★★.doFilter메서드는 항상 엔드포인트가 호출되기 전에 실행되며 나중에 엔드포인트가 호출됩니다.

할 때 합니다.accountFeignClient.getData("Bearer " + tokenString, ids);데이터베이스(또는 보관한 다른 위치)에서 가져와 여기에 설정할 수 있습니다.

답변은 받았습니다만, 더 나은 옵션을 기다리겠습니다.@Request @Request requestrequestrequestrequestrequest requestrequestrequestrequest requestrequestrequest requestrequest 。의 헤더를 토큰을 .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);
}

선가 읽었는데, '아주머니'라는 게 요.Interceptor @Request @Request를 입력하지 됩니다.헤더를 만, 더 좋은 할 수 , 의 헤더를 .하지만 그것이 해결책인지, 적절한 사용법인지 모르겠습니다.누군가 더 나은 것을 가지고 이것을 할 수 있다면, 당신의 것을 답으로 받아들이겠습니다.

아래 @stacker의 답변은 맞는 것 같습니다만, 뭔가 불완전하고, 「Feign에서의 사용법」이 없는 것 같습니다.

예시를 , 이 예시를 수신할 수 하겠습니다.User-Agent를 개시해, 을 「」로 합니다.Feign

「 」를 사용하고 있는 .Feign으로 하는 Feign 할 수 .

@Configuration
@EnableFeignClients(
    defaultConfiguration = DefaultFeignConfiguration.class
)
public class FeignConfig
{
}
@Configuration
@Import(FeignClientsConfiguration.class)
public class DefaultFeignConfiguration
{
    @Bean
    public RequestInterceptor userAgentHeaderInterceptor() {
        return UserAgentHeaderInterceptor();
    } 
}

User-Agent interceptor 클래스입니다.

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

이 기본 .이러한 인터셉터를 작성하려면 , 「인터셉터와 하게 작성됩니다.UserAgentHeaderInterceptor

프론트 엔드에서 반환되는 헤더 정보를 가져오려면 다음 주석을 사용합니다.@RequestHeader("Authorization") 문자열 토큰

예:

@GetMapping("/hello")
    public void hello(@RequestHeader("Authorization") String token){

유틸리티 클래스에서 이 간단한 정적 메서드를 생성하여 이 메서드를 직접 재사용할 수 있습니다.

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

언급URL : https://stackoverflow.com/questions/65019801/how-to-get-bearer-token-from-header-of-a-request-in-java-spring-boot

반응형