在微服务开发过程中,安全方面使用的是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上下文中
充满鲜花的世界到底在哪里