在微服務開發過程中,安全方面使用的是Spring Security OAuth2.0令牌認證,在進行服務與服務之間調用時,使用的Feign客戶端,如果不通過Feign攔截器來添加請求頭信息。下游服務是接收不到認證過的token令牌,無法進行身份驗證。
-
定義Feign攔截器,實現 RequestInterceptor 接口
@Slf4j public class FeignRequestInterceptor implements RequestInterceptor { /** * 微服務之間傳遞的唯一標識 */ public static final String X_REQUEST_ID = "X-Request-Id"; @Override public void apply(RequestTemplate template) { HttpServletRequest httpServletRequest = getHttpServletRequest(); if (httpServletRequest != null) { //獲取頭信息 Map<String, String> headers = getHeaders(httpServletRequest); // 傳遞所有請求頭,防止部分丟失 Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator(); //將請求的頭信息放入到RequestTemplate 的頭信息中,當使用RequestTemplate發起請求時會自動添加頭信息 while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); template.header(entry.getKey(), entry.getValue()); } // 微服務之間傳遞的唯一標識,區分大小寫所以通過httpServletRequest獲取 if (httpServletRequest.getHeader(X_REQUEST_ID) == null) { String sid = String.valueOf(UUID.randomUUID()); template.header(X_REQUEST_ID, sid); } log.debug("FeignRequestInterceptor:{}", template.toString()); } } /** * RequestContextHolder 中獲取 HttpServletRequest對象 * * @return */ private HttpServletRequest getHttpServletRequest() { try { return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); } catch (Exception e) { return null; } } /** * 獲取頭信息 * * @param request * @return */ private Map<String, String> getHeaders(HttpServletRequest request) { Map<String, String> map = new LinkedHashMap<>(); Enumeration<String> enumeration = request.getHeaderNames(); if (enumeration != null) { while (enumeration.hasMoreElements()) { String key = enumeration.nextElement(); String value = request.getHeader(key); map.put(key, value); } } return map; } }
-
配置Bean
@Bean @ConditionalOnMissingBean(FeignRequestInterceptor.class) public RequestInterceptor feignRequestInterceptor() { FeignRequestInterceptor interceptor = new FeignRequestInterceptor(); log.info("FeignRequestInterceptor [{}]", interceptor); return interceptor; }
在每次進行調用時,會經過 OAuth2AuthenticationProcessingFilter 過濾器的 doFilter方法進行token驗證,通過 tokenExtract 的 extract 方法抽取攜帶在請求中的令牌信息。
-
OAuth2AuthenticationProcessingFilter 的 doFilter
如果認證成功,放入SpringContext上下文中