首頁 > 軟體

feign之間傳遞oauth2 token的問題及解決方案

2022-03-15 16:02:37

feign之間傳遞oauth2 token問題

在微服務架構裡,服務與服務之間的呼叫一般用feign就可以實現,它是一種視覺化的rpc,並且整合了ribbon的負載均衡能力,所以很受歡迎。

授權服務

在授權服務裡,使用者通過使用者名稱密碼,或者手機和驗證碼等方式登陸之後,在http頭裡會有授權的標識,在使用者端呼叫時,需要新增當時有效的token才可以正常存取被授權的頁面。

Content-Type:application/jsonAuthorization:Bearer d79c064c-8675-4047-a119-fac692e447e8

而在業務層裡,服務與服務之間使用feign來實現呼叫,而授權的程式碼我們可以通過攔截器實現,在feign請求之前,把當前服務的token新增到目標服務的請求頭就可以了,一般是這樣實現的。

/**
 * 傳送FeignClient設定Header資訊.
 * http://www.itmuch.com/spring-cloud-sum/hystrix-threadlocal/
 * Hystrix傳播ThreadLocal物件
 */
@Component
public class TokenFeignClientInterceptor implements RequestInterceptor {
  /**
   * token放在請求頭.
   *
   * @param requestTemplate 請求引數
   */
  @Override
  public void apply(RequestTemplate requestTemplate) {
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    if (requestAttributes != null) {
      HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
      String token = request.getHeader(TokenContext.KEY_OAUTH2_TOKEN);
      requestTemplate.header(TokenContext.KEY_OAUTH2_TOKEN,
          new String[] {token});
    }
  }
}

上面的攔截器程式碼沒有什麼問題,也很好理解,但事實上,當你的feign開啟了hystrix功能,如果開啟了,需要把hystrix的策略進行修改,預設是THREAD的,這個級別時ThreadLocal是空的,所以你的授權不能傳給feign的攔截器.

hystrix.command.default.execution.isolation.strategy: SEMAPHORE 

資源專案裡獲取當前使用者

在另一個專案,需要其它獲取當前使用者,需要使用下面的程式碼。

先設定一個授權的地址

security:
  oauth2:
    resource:
      id: user
      user-info-uri: http://${auth.host:localhost}:${auth.port:8002}/user # 這裡是授權服務的地址,即auth-service
      prefer-token-info: false
auth:
  host: localhost  #這個不可以用eureka裡的服務名,只能使用docker-compose裡的服務名
  port: 8002

下面的程式碼用來獲取當前使用者

 Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String user = objectMapper.writeValueAsString(authentication.getPrincipal());

主要對feign的請求頭傳遞資訊進行講解分享給大家,各位多注意下!

oauth2 feign報401的錯誤

報錯問題:

feign.FeignException: status 401 reading UserFeign#queryUser(Long,String,String,String,Integer,Integer,Integer)

解決方法

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
@Configuration
public class FeignOauth2RequestInterceptor implements RequestInterceptor {
    private final String AUTHORIZATION_HEADER = "Authorization";
    private final String BEARER_TOKEN_TYPE = "Bearer";
    @Override
    public void apply(RequestTemplate requestTemplate) {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication authentication = securityContext.getAuthentication();
        if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
            requestTemplate.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
        }
    }
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com