陆小叁
这是一个充满鲜花的世界

在微服务开发过程中,安全方面使用的是Spring Security OAuth2.0令牌认证,在进行服务与服务之间调用时,使用的Feign客户端,如果不通过Feign拦截器来添加请求头信息。下游服务是接收不到认证过的token令牌,无法进行身份验证。

  1. 定义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;
        }
    
    }
    
  2. 配置Bean

    @Bean
        @ConditionalOnMissingBean(FeignRequestInterceptor.class)
        public RequestInterceptor feignRequestInterceptor() {
    
            FeignRequestInterceptor interceptor = new FeignRequestInterceptor();
            log.info("FeignRequestInterceptor [{}]", interceptor);
            return interceptor;
        }
    

    在每次进行调用时,会经过 OAuth2AuthenticationProcessingFilter 过滤器的 doFilter方法进行token验证,通过 tokenExtract 的 extract 方法抽取携带在请求中的令牌信息。

  3. OAuth2AuthenticationProcessingFilter 的 doFilter
    在这里插入图片描述

    如果认证成功,放入SpringContext上下文中

    在这里插入图片描述

posted on 2021-04-23 12:52  陆小叁  阅读(2208)  评论(0编辑  收藏  举报