Commit 242ce79393632bbffefa93c26128e36a7f729a77

Authored by zhangdaiscott
1 parent ef4a293f

HW21-0499 表字典接口存在SQL注入漏洞,增加签名拦截器

jeecg-boot/README.md
... ... @@ -43,7 +43,7 @@ Jeecg-Boot 低代码开发平台
43 43  
44 44 - 常见问题: [http://jeecg.com/doc/qa](http://jeecg.com/doc/qa)
45 45  
46   -- QQ交流群 : ④774126647、③816531124(满)、①284271917、②769925425
  46 +- QQ交流群 : ③816531124、①284271917、②769925425
47 47  
48 48  
49 49 ## 专项文档
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/config/FeignConfig.java
1 1 package org.jeecg.config;
2 2  
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.serializer.SerializerFeature;
  5 +import com.alibaba.fastjson.support.config.FastJsonConfig;
  6 +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
  7 +import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer;
3 8 import feign.Feign;
4 9 import feign.Logger;
5 10 import feign.RequestInterceptor;
  11 +import feign.codec.Decoder;
6 12 import feign.codec.Encoder;
7 13 import feign.form.spring.SpringFormEncoder;
8 14 import lombok.extern.slf4j.Slf4j;
9 15 import org.jeecg.common.constant.CommonConstant;
  16 +import org.jeecg.common.util.DateUtils;
  17 +import org.jeecg.common.util.PathMatcherUtil;
  18 +import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
  19 +import org.jeecg.config.sign.util.HttpUtils;
  20 +import org.jeecg.config.sign.util.SignUtil;
10 21 import org.springframework.beans.factory.ObjectFactory;
11 22 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
12 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
13 24 import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
14 25 import org.springframework.cloud.openfeign.FeignAutoConfiguration;
  26 +import org.springframework.cloud.openfeign.support.SpringDecoder;
15 27 import org.springframework.cloud.openfeign.support.SpringEncoder;
16 28 import org.springframework.context.annotation.Bean;
17 29 import org.springframework.context.annotation.Configuration;
18 30 import org.springframework.context.annotation.Primary;
19 31 import org.springframework.context.annotation.Scope;
  32 +import org.springframework.http.MediaType;
20 33 import org.springframework.web.context.request.RequestContextHolder;
21 34 import org.springframework.web.context.request.ServletRequestAttributes;
22   -import javax.servlet.http.HttpServletRequest;
23 35  
  36 +import javax.servlet.http.HttpServletRequest;
  37 +import java.io.IOException;
  38 +import java.util.ArrayList;
  39 +import java.util.Arrays;
  40 +import java.util.List;
  41 +import java.util.SortedMap;
24 42  
25 43 @ConditionalOnClass(Feign.class)
26 44 @AutoConfigureBefore(FeignAutoConfiguration.class)
... ... @@ -37,11 +55,36 @@ public class FeignConfig {
37 55 log.info("Feign request: {}", request.getRequestURI());
38 56 // 将token信息放入header中
39 57 String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
40   - if(token==null){
  58 + if(token==null || "".equals(token)){
41 59 token = request.getParameter("token");
42 60 }
43 61 log.info("Feign request token: {}", token);
44 62 requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
  63 +
  64 + //根据URL地址过滤请求 【字典表参数签名验证】
  65 + if (PathMatcherUtil.matches(Arrays.asList(SignAuthConfiguration.urlList),requestTemplate.path())) {
  66 + try {
  67 + log.info("============================ [begin] fegin api url ============================");
  68 + log.info(requestTemplate.path());
  69 + log.info(requestTemplate.method());
  70 + String queryLine = requestTemplate.queryLine();
  71 + if(queryLine!=null && queryLine.startsWith("?")){
  72 + queryLine = queryLine.substring(1);
  73 + }
  74 + log.info(queryLine);
  75 + if(requestTemplate.body()!=null){
  76 + log.info(new String(requestTemplate.body()));
  77 + }
  78 + SortedMap<String, String> allParams = HttpUtils.getAllParams(requestTemplate.path(),queryLine,requestTemplate.body(),requestTemplate.method());
  79 + String sign = SignUtil.getParamsSign(allParams);
  80 + log.info(" Feign request params sign: {}",sign);
  81 + log.info("============================ [end] fegin api url ============================");
  82 + requestTemplate.header(CommonConstant.X_SIGN, sign);
  83 + requestTemplate.header(CommonConstant.X_TIMESTAMP, DateUtils.getCurrentTimestamp().toString());
  84 + } catch (IOException e) {
  85 + e.printStackTrace();
  86 + }
  87 + }
45 88 }
46 89 };
47 90 }
... ... @@ -72,4 +115,42 @@ public class FeignConfig {
72 115 public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
73 116 return new SpringFormEncoder(new SpringEncoder(messageConverters));
74 117 }
  118 +
  119 + // update-begin--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
  120 + @Bean
  121 + public Encoder feignEncoder() {
  122 + return new SpringEncoder(feignHttpMessageConverter());
  123 + }
  124 +
  125 + @Bean
  126 + public Decoder feignDecoder() {
  127 + return new SpringDecoder(feignHttpMessageConverter());
  128 + }
  129 +
  130 + /**
  131 + * 设置解码器为fastjson
  132 + *
  133 + * @return
  134 + */
  135 + private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
  136 + final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
  137 + return () -> httpMessageConverters;
  138 + }
  139 +
  140 + private FastJsonHttpMessageConverter getFastJsonConverter() {
  141 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
  142 +
  143 + List<MediaType> supportedMediaTypes = new ArrayList<>();
  144 + MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE);
  145 + supportedMediaTypes.add(mediaTypeJson);
  146 + converter.setSupportedMediaTypes(supportedMediaTypes);
  147 + FastJsonConfig config = new FastJsonConfig();
  148 + config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer());
  149 + config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
  150 + converter.setFastJsonConfig(config);
  151 +
  152 + return converter;
  153 + }
  154 + // update-end--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
  155 +
75 156 }
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
... ... @@ -290,6 +290,8 @@ public interface CommonConstant {
290 290  
291 291  
292 292 public final static String X_ACCESS_TOKEN = "X-Access-Token";
  293 + public final static String X_SIGN = "X-Sign";
  294 + public final static String X_TIMESTAMP = "X-TIMESTAMP";
293 295  
294 296 /**
295 297 * 多租户 请求头
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PathMatcherUtil.java 0 → 100644
  1 +package org.jeecg.common.util;
  2 +
  3 +import org.springframework.util.AntPathMatcher;
  4 +
  5 +import java.util.Collection;
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * 使用Spring自身提供的地址匹配工具匹配URL
  10 + */
  11 +public class PathMatcherUtil {
  12 +
  13 + public static void main(String[] args) {
  14 + String url = "/sys/dict/loadDictOrderByValue/tree,s2,2";
  15 + String p = "/sys/dict/loadDictOrderByValue/*";
  16 +
  17 + System.out.println(PathMatcherUtil.match(p,url));
  18 + }
  19 +
  20 + /**
  21 + * 实际验证路径匹配权限
  22 + *
  23 + * @param matchPath 权限url
  24 + * @param path 访问路径
  25 + * @return 是否拥有权限
  26 + */
  27 + public static boolean match(String matchPath, String path) {
  28 + SpringAntMatcher springAntMatcher = new SpringAntMatcher(matchPath, true);
  29 + return springAntMatcher.matches(path);
  30 + }
  31 +
  32 + /**
  33 + * 实际验证路径匹配权限
  34 + *
  35 + * @param list 权限url
  36 + * @param path 访问路径
  37 + * @return 是否拥有权限
  38 + */
  39 + public static boolean matches(Collection<String> list, String path) {
  40 + for (String s : list) {
  41 + SpringAntMatcher springAntMatcher = new SpringAntMatcher(s, true);
  42 + if (springAntMatcher.matches(path)) {
  43 + return true;
  44 + }
  45 + }
  46 + return false;
  47 + }
  48 +
  49 + /**
  50 + * 地址表达式匹配工具
  51 + */
  52 + private static class SpringAntMatcher implements Matcher {
  53 + private final AntPathMatcher antMatcher;
  54 + private final String pattern;
  55 +
  56 + private SpringAntMatcher(String pattern, boolean caseSensitive) {
  57 + this.pattern = pattern;
  58 + this.antMatcher = createMatcher(caseSensitive);
  59 + }
  60 +
  61 + @Override
  62 + public boolean matches(String path) {
  63 + return this.antMatcher.match(this.pattern, path);
  64 + }
  65 +
  66 + @Override
  67 + public Map<String, String> extractUriTemplateVariables(String path) {
  68 + return this.antMatcher.extractUriTemplateVariables(this.pattern, path);
  69 + }
  70 +
  71 + private static AntPathMatcher createMatcher(boolean caseSensitive) {
  72 + AntPathMatcher matcher = new AntPathMatcher();
  73 + matcher.setTrimTokens(false);
  74 + matcher.setCaseSensitive(caseSensitive);
  75 + return matcher;
  76 + }
  77 + }
  78 +
  79 + private interface Matcher {
  80 + boolean matches(String var1);
  81 +
  82 + Map<String, String> extractUriTemplateVariables(String var1);
  83 + }
  84 +}
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
... ... @@ -6,11 +6,14 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
6 6 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7 7  
8 8 /**
9   - * online 拦截器配置
  9 + * 签名 拦截器配置
10 10 */
11 11 @Configuration
12 12 public class SignAuthConfiguration implements WebMvcConfigurer {
13   -
  13 + public static String[] urlList = new String[] {"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*",
  14 + "/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData",
  15 + "/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys",
  16 + "/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"};
14 17 @Bean
15 18 public SignAuthInterceptor signAuthInterceptor() {
16 19 return new SignAuthInterceptor();
... ... @@ -18,10 +21,6 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
18 21  
19 22 @Override
20 23 public void addInterceptors(InterceptorRegistry registry) {
21   - String[] inculudes = new String[] {"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*",
22   - "/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData",
23   - "/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys",
24   - "/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"};
25   - registry.addInterceptor(signAuthInterceptor()).addPathPatterns(inculudes);
  24 + registry.addInterceptor(signAuthInterceptor()).addPathPatterns(urlList);
26 25 }
27 26 }
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
1 1 package org.jeecg.config.sign.interceptor;
2 2  
3 3  
4   -import java.io.PrintWriter;
5   -import java.util.SortedMap;
6   -
7   -import javax.servlet.http.HttpServletRequest;
8   -import javax.servlet.http.HttpServletResponse;
9   -
  4 +import com.alibaba.fastjson.JSON;
  5 +import lombok.extern.slf4j.Slf4j;
10 6 import org.jeecg.common.api.vo.Result;
  7 +import org.jeecg.common.constant.CommonConstant;
11 8 import org.jeecg.common.util.DateUtils;
12 9 import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
13 10 import org.jeecg.config.sign.util.HttpUtils;
14 11 import org.jeecg.config.sign.util.SignUtil;
15 12 import org.springframework.web.servlet.HandlerInterceptor;
16 13  
17   -import com.alibaba.fastjson.JSON;
18   -
19   -import lombok.extern.slf4j.Slf4j;
  14 +import javax.servlet.http.HttpServletRequest;
  15 +import javax.servlet.http.HttpServletResponse;
  16 +import java.io.PrintWriter;
  17 +import java.util.SortedMap;
20 18  
21 19 /**
22 20 * 签名拦截器
... ... @@ -31,13 +29,13 @@ public class SignAuthInterceptor implements HandlerInterceptor {
31 29  
32 30 @Override
33 31 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
34   - log.debug("request URI = " + request.getRequestURI());
  32 + log.info("request URI = " + request.getRequestURI());
35 33 HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
36 34 //获取全部参数(包括URL和body上的)
37 35 SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
38 36 //对参数进行签名验证
39   - String headerSign = request.getHeader("X-Sign");
40   - String timesTamp = request.getHeader("X-TIMESTAMP");
  37 + String headerSign = request.getHeader(CommonConstant.X_SIGN);
  38 + String timesTamp = request.getHeader(CommonConstant.X_TIMESTAMP);
41 39  
42 40 //1.校验时间有消息
43 41 try {
... ... @@ -60,15 +58,6 @@ public class SignAuthInterceptor implements HandlerInterceptor {
60 58 } else {
61 59 log.error("request URI = " + request.getRequestURI());
62 60 log.error("Sign 签名校验失败!Header Sign : {}",headerSign);
63   -// //打印日志参数
64   -// Set<String> keySet = allParams.keySet();
65   -// Iterator<String> paramIt = keySet.iterator();
66   -// while(paramIt.hasNext()){
67   -// String pkey = paramIt.next();
68   -// String pval = allParams.get(pkey);
69   -// log.error(" ["+pkey+":"+pval+"] ");
70   -// }
71   -
72 61 //校验失败返回前端
73 62 response.setCharacterEncoding("UTF-8");
74 63 response.setContentType("application/json; charset=utf-8");
... ...
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java
1 1 package org.jeecg.config.sign.util;
2 2  
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import org.jeecg.common.util.oConvertUtils;
  5 +import org.springframework.http.HttpMethod;
  6 +
  7 +import javax.servlet.http.HttpServletRequest;
3 8 import java.io.BufferedReader;
4 9 import java.io.IOException;
5 10 import java.io.InputStreamReader;
... ... @@ -10,35 +15,28 @@ import java.util.Map;
10 15 import java.util.SortedMap;
11 16 import java.util.TreeMap;
12 17  
13   -import javax.servlet.http.HttpServletRequest;
14   -
15   -import org.jeecg.common.util.oConvertUtils;
16   -import org.springframework.http.HttpMethod;
17   -
18   -import com.alibaba.fastjson.JSONObject;
19   -
20 18 /**
21 19 * http 工具类 获取请求中的参数
22   - *
23   - * @author show
24   - * @date 14:23 2019/5/29
  20 + *
  21 + * @author jeecg
  22 + * @date 20210621
25 23 */
26 24 public class HttpUtils {
27 25  
28 26 /**
29 27 * 将URL的参数和body参数合并
30   - *
31   - * @author show
32   - * @date 14:24 2019/5/29
  28 + *
  29 + * @author jeecg
  30 + * @date 20210621
33 31 * @param request
34 32 */
35 33 public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException {
36 34  
37 35 SortedMap<String, String> result = new TreeMap<>();
38 36 // 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
39   - String pathVariable = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/")+1);
40   - if(pathVariable.contains(",")){
41   - result.put(SignUtil.xPathVariable,pathVariable);
  37 + String pathVariable = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1);
  38 + if (pathVariable.contains(",")) {
  39 + result.put(SignUtil.xPathVariable, pathVariable);
42 40 }
43 41 // 获取URL上的参数
44 42 Map<String, String> urlParams = getUrlParams(request);
... ... @@ -60,10 +58,44 @@ public class HttpUtils {
60 58 }
61 59  
62 60 /**
  61 + * 将URL的参数和body参数合并
  62 + *
  63 + * @author jeecg
  64 + * @date 20210621
  65 + * @param queryString
  66 + */
  67 + public static SortedMap<String, String> getAllParams(String url, String queryString, byte[] body, String method)
  68 + throws IOException {
  69 +
  70 + SortedMap<String, String> result = new TreeMap<>();
  71 + // 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
  72 + String pathVariable = url.substring(url.lastIndexOf("/") + 1);
  73 + if (pathVariable.contains(",")) {
  74 + result.put(SignUtil.xPathVariable, pathVariable);
  75 + }
  76 + // 获取URL上的参数
  77 + Map<String, String> urlParams = getUrlParams(queryString);
  78 + for (Map.Entry entry : urlParams.entrySet()) {
  79 + result.put((String)entry.getKey(), (String)entry.getValue());
  80 + }
  81 + Map<String, String> allRequestParam = new HashMap<>(16);
  82 + // get请求不需要拿body参数
  83 + if (!HttpMethod.GET.name().equals(method)) {
  84 + allRequestParam = getAllRequestParam(body);
  85 + }
  86 + // 将URL的参数和body参数进行合并
  87 + if (allRequestParam != null) {
  88 + for (Map.Entry entry : allRequestParam.entrySet()) {
  89 + result.put((String)entry.getKey(), (String)entry.getValue());
  90 + }
  91 + }
  92 + return result;
  93 + }
  94 +
  95 + /**
63 96 * 获取 Body 参数
64   - *
65   - * @author show
66   - * @date 15:04 2019/5/30
  97 + *
  98 + * @date 15:04 20210621
67 99 * @param request
68 100 */
69 101 public static Map<String, String> getAllRequestParam(final HttpServletRequest request) throws IOException {
... ... @@ -80,14 +112,28 @@ public class HttpUtils {
80 112 }
81 113  
82 114 /**
  115 + * 获取 Body 参数
  116 + *
  117 + * @date 15:04 20210621
  118 + * @param body
  119 + */
  120 + public static Map<String, String> getAllRequestParam(final byte[] body) throws IOException {
  121 + if(body==null){
  122 + return null;
  123 + }
  124 + String wholeStr = new String(body);
  125 + // 转化成json对象
  126 + return JSONObject.parseObject(wholeStr.toString(), Map.class);
  127 + }
  128 +
  129 + /**
83 130 * 将URL请求参数转换成Map
84   - *
85   - * @author show
  131 + *
86 132 * @param request
87 133 */
88 134 public static Map<String, String> getUrlParams(HttpServletRequest request) {
89 135 Map<String, String> result = new HashMap<>(16);
90   - if(oConvertUtils.isEmpty(request.getQueryString())){
  136 + if (oConvertUtils.isEmpty(request.getQueryString())) {
91 137 return result;
92 138 }
93 139 String param = "";
... ... @@ -103,4 +149,28 @@ public class HttpUtils {
103 149 }
104 150 return result;
105 151 }
  152 +
  153 + /**
  154 + * 将URL请求参数转换成Map
  155 + *
  156 + * @param queryString
  157 + */
  158 + public static Map<String, String> getUrlParams(String queryString) {
  159 + Map<String, String> result = new HashMap<>(16);
  160 + if (oConvertUtils.isEmpty(queryString)) {
  161 + return result;
  162 + }
  163 + String param = "";
  164 + try {
  165 + param = URLDecoder.decode(queryString, "utf-8");
  166 + } catch (UnsupportedEncodingException e) {
  167 + e.printStackTrace();
  168 + }
  169 + String[] params = param.split("&");
  170 + for (String s : params) {
  171 + int index = s.indexOf("=");
  172 + result.put(s.substring(0, index), s.substring(index + 1));
  173 + }
  174 + return result;
  175 + }
106 176 }
107 177 \ No newline at end of file
... ...
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/java/org/jeecg/config/FeignConfig.java
1 1 package org.jeecg.config;
2 2  
3   -import feign.Feign;
4   -import feign.Logger;
5   -import feign.RequestInterceptor;
6   -import feign.codec.Encoder;
7   -import feign.form.spring.SpringFormEncoder;
8   -import lombok.extern.slf4j.Slf4j;
  3 +import java.io.IOException;
  4 +import java.util.ArrayList;
  5 +import java.util.Arrays;
  6 +import java.util.List;
  7 +import java.util.SortedMap;
  8 +
  9 +import javax.servlet.http.HttpServletRequest;
  10 +
9 11 import org.jeecg.common.constant.CommonConstant;
10   -import org.jeecg.config.FeignConfig;
  12 +import org.jeecg.common.util.DateUtils;
  13 +import org.jeecg.common.util.PathMatcherUtil;
  14 +import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
  15 +import org.jeecg.config.sign.util.HttpUtils;
  16 +import org.jeecg.config.sign.util.SignUtil;
11 17 import org.springframework.beans.factory.ObjectFactory;
12 18 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
13 19 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
14   -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
15 20 import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
16 21 import org.springframework.cloud.openfeign.FeignAutoConfiguration;
  22 +import org.springframework.cloud.openfeign.support.SpringDecoder;
17 23 import org.springframework.cloud.openfeign.support.SpringEncoder;
18 24 import org.springframework.context.annotation.Bean;
19 25 import org.springframework.context.annotation.Configuration;
20 26 import org.springframework.context.annotation.Primary;
21 27 import org.springframework.context.annotation.Scope;
  28 +import org.springframework.http.MediaType;
22 29 import org.springframework.web.context.request.RequestContextHolder;
23 30 import org.springframework.web.context.request.ServletRequestAttributes;
24   -import javax.servlet.http.HttpServletRequest;
25 31  
  32 +import com.alibaba.fastjson.JSON;
  33 +import com.alibaba.fastjson.serializer.SerializerFeature;
  34 +import com.alibaba.fastjson.support.config.FastJsonConfig;
  35 +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
  36 +import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer;
  37 +
  38 +import feign.Feign;
  39 +import feign.Logger;
  40 +import feign.RequestInterceptor;
  41 +import feign.codec.Decoder;
  42 +import feign.codec.Encoder;
  43 +import feign.form.spring.SpringFormEncoder;
  44 +import lombok.extern.slf4j.Slf4j;
26 45  
27 46 @ConditionalOnClass(Feign.class)
28 47 @AutoConfigureBefore(FeignAutoConfiguration.class)
... ... @@ -39,11 +58,36 @@ public class FeignConfig {
39 58 log.info("Feign request: {}", request.getRequestURI());
40 59 // 将token信息放入header中
41 60 String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
42   - if(token==null){
  61 + if(token==null || "".equals(token)){
43 62 token = request.getParameter("token");
44 63 }
45 64 log.info("Feign request token: {}", token);
46 65 requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
  66 +
  67 + //根据URL地址过滤请求 【字典表参数签名验证】
  68 + if (PathMatcherUtil.matches(Arrays.asList(SignAuthConfiguration.urlList),requestTemplate.path())) {
  69 + try {
  70 + log.info("============================ [begin] fegin starter url ============================");
  71 + log.info(requestTemplate.path());
  72 + log.info(requestTemplate.method());
  73 + String queryLine = requestTemplate.queryLine();
  74 + if(queryLine!=null && queryLine.startsWith("?")){
  75 + queryLine = queryLine.substring(1);
  76 + }
  77 + log.info(queryLine);
  78 + if(requestTemplate.body()!=null){
  79 + log.info(new String(requestTemplate.body()));
  80 + }
  81 + SortedMap<String, String> allParams = HttpUtils.getAllParams(requestTemplate.path(),queryLine,requestTemplate.body(),requestTemplate.method());
  82 + String sign = SignUtil.getParamsSign(allParams);
  83 + log.info(" Feign request params sign: {}",sign);
  84 + log.info("============================ [end] fegin starter url ============================");
  85 + requestTemplate.header(CommonConstant.X_SIGN, sign);
  86 + requestTemplate.header(CommonConstant.X_TIMESTAMP, DateUtils.getCurrentTimestamp().toString());
  87 + } catch (IOException e) {
  88 + e.printStackTrace();
  89 + }
  90 + }
47 91 }
48 92 };
49 93 }
... ... @@ -74,4 +118,42 @@ public class FeignConfig {
74 118 public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
75 119 return new SpringFormEncoder(new SpringEncoder(messageConverters));
76 120 }
  121 +
  122 + // update-begin--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
  123 + @Bean
  124 + public Encoder feignEncoder() {
  125 + return new SpringEncoder(feignHttpMessageConverter());
  126 + }
  127 +
  128 + @Bean
  129 + public Decoder feignDecoder() {
  130 + return new SpringDecoder(feignHttpMessageConverter());
  131 + }
  132 +
  133 + /**
  134 + * 设置解码器为fastjson
  135 + *
  136 + * @return
  137 + */
  138 + private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
  139 + final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
  140 + return () -> httpMessageConverters;
  141 + }
  142 +
  143 + private FastJsonHttpMessageConverter getFastJsonConverter() {
  144 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
  145 +
  146 + List<MediaType> supportedMediaTypes = new ArrayList<>();
  147 + MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE);
  148 + supportedMediaTypes.add(mediaTypeJson);
  149 + converter.setSupportedMediaTypes(supportedMediaTypes);
  150 + FastJsonConfig config = new FastJsonConfig();
  151 + config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer());
  152 + config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
  153 + converter.setFastJsonConfig(config);
  154 +
  155 + return converter;
  156 + }
  157 + // update-end--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
  158 +
77 159 }
... ...