Commit ef4a293f39226a685820ec3418783ec8d6279e1d
1 parent
33adbc52
HW21-0499 表字典接口存在SQL注入漏洞,增加签名拦截器
online表单数据源配置,数据库类型识别错误 #2671
Showing
10 changed files
with
534 additions
and
5 deletions
ant-design-vue-jeecg/src/api/manage.js
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | import { axios } from '@/utils/request' | 2 | import { axios } from '@/utils/request' |
3 | +import signMd5Utils from '@/utils/encryption/signMd5Utils' | ||
3 | 4 | ||
4 | const api = { | 5 | const api = { |
5 | user: '/mock/api/user', | 6 | user: '/mock/api/user', |
@@ -13,19 +14,29 @@ export default api | @@ -13,19 +14,29 @@ export default api | ||
13 | 14 | ||
14 | //post | 15 | //post |
15 | export function postAction(url,parameter) { | 16 | export function postAction(url,parameter) { |
17 | + let sign = signMd5Utils.getSign(url, parameter); | ||
18 | + //将签名和时间戳,添加在请求接口 Header | ||
19 | + let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()}; | ||
20 | + | ||
16 | return axios({ | 21 | return axios({ |
17 | url: url, | 22 | url: url, |
18 | method:'post' , | 23 | method:'post' , |
19 | - data: parameter | 24 | + data: parameter, |
25 | + headers: signHeader | ||
20 | }) | 26 | }) |
21 | } | 27 | } |
22 | 28 | ||
23 | //post method= {post | put} | 29 | //post method= {post | put} |
24 | export function httpAction(url,parameter,method) { | 30 | export function httpAction(url,parameter,method) { |
31 | + let sign = signMd5Utils.getSign(url, parameter); | ||
32 | + //将签名和时间戳,添加在请求接口 Header | ||
33 | + let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()}; | ||
34 | + | ||
25 | return axios({ | 35 | return axios({ |
26 | url: url, | 36 | url: url, |
27 | method:method , | 37 | method:method , |
28 | - data: parameter | 38 | + data: parameter, |
39 | + headers: signHeader | ||
29 | }) | 40 | }) |
30 | } | 41 | } |
31 | 42 | ||
@@ -40,10 +51,15 @@ export function putAction(url,parameter) { | @@ -40,10 +51,15 @@ export function putAction(url,parameter) { | ||
40 | 51 | ||
41 | //get | 52 | //get |
42 | export function getAction(url,parameter) { | 53 | export function getAction(url,parameter) { |
54 | + let sign = signMd5Utils.getSign(url, parameter); | ||
55 | + //将签名和时间戳,添加在请求接口 Header | ||
56 | + let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()}; | ||
57 | + | ||
43 | return axios({ | 58 | return axios({ |
44 | url: url, | 59 | url: url, |
45 | method: 'get', | 60 | method: 'get', |
46 | - params: parameter | 61 | + params: parameter, |
62 | + headers: signHeader | ||
47 | }) | 63 | }) |
48 | } | 64 | } |
49 | 65 |
ant-design-vue-jeecg/src/utils/encryption/signMd5Utils.js
0 → 100644
1 | +import md5 from 'md5' | ||
2 | +//签名密钥串(前后端要一致,正式发布请自行修改) | ||
3 | +const signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | ||
4 | + | ||
5 | +export default class signMd5Utils { | ||
6 | + /** | ||
7 | + * json参数升序 | ||
8 | + * @param jsonObj 发送参数 | ||
9 | + */ | ||
10 | + | ||
11 | + static sortAsc(jsonObj) { | ||
12 | + let arr = new Array(); | ||
13 | + let num = 0; | ||
14 | + for (let i in jsonObj) { | ||
15 | + arr[num] = i; | ||
16 | + num++; | ||
17 | + } | ||
18 | + let sortArr = arr.sort(); | ||
19 | + let sortObj = {}; | ||
20 | + for (let i in sortArr) { | ||
21 | + sortObj[sortArr[i]] = jsonObj[sortArr[i]]; | ||
22 | + } | ||
23 | + return sortObj; | ||
24 | + } | ||
25 | + | ||
26 | + | ||
27 | + /** | ||
28 | + * @param url 请求的url,应该包含请求参数(url的?后面的参数) | ||
29 | + * @param requestParams 请求参数(POST的JSON参数) | ||
30 | + * @returns {string} 获取签名 | ||
31 | + */ | ||
32 | + static getSign(url, requestParams) { | ||
33 | + let urlParams = this.parseQueryString(url); | ||
34 | + let jsonObj = this.mergeObject(urlParams, requestParams); | ||
35 | + //console.log("sign jsonObj: ",jsonObj) | ||
36 | + let requestBody = this.sortAsc(jsonObj); | ||
37 | + console.log("sign requestBody: ",requestBody) | ||
38 | + return md5(JSON.stringify(requestBody) + signatureSecret).toUpperCase(); | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * @param url 请求的url | ||
43 | + * @returns {{}} 将url中请求参数组装成json对象(url的?后面的参数) | ||
44 | + */ | ||
45 | + static parseQueryString(url) { | ||
46 | + let urlReg = /^[^\?]+\?([\w\W]+)$/, | ||
47 | + paramReg = /([^&=]+)=([\w\W]*?)(&|$|#)/g, | ||
48 | + urlArray = urlReg.exec(url), | ||
49 | + result = {}; | ||
50 | + | ||
51 | + // 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username | ||
52 | + let lastpathVariable = url.substring(url.lastIndexOf('/') + 1); | ||
53 | + if(lastpathVariable.includes(",")){ | ||
54 | + if(lastpathVariable.includes("?")){ | ||
55 | + lastpathVariable = lastpathVariable.substring(0, lastpathVariable.indexOf("?")); | ||
56 | + } | ||
57 | + result["x-path-variable"] = lastpathVariable; | ||
58 | + } | ||
59 | + if (urlArray && urlArray[1]) { | ||
60 | + let paramString = urlArray[1], paramResult; | ||
61 | + while ((paramResult = paramReg.exec(paramString)) != null) { | ||
62 | + //数字值转为string类型,前后端加密规则保持一致 | ||
63 | + if(this.myIsNaN(paramResult[2])){ | ||
64 | + paramResult[2] = paramResult[2].toString() | ||
65 | + } | ||
66 | + result[paramResult[1]] = paramResult[2]; | ||
67 | + } | ||
68 | + } | ||
69 | + return result; | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * @returns {*} 将两个对象合并成一个 | ||
74 | + */ | ||
75 | + static mergeObject(objectOne, objectTwo) { | ||
76 | + if (objectTwo && Object.keys(objectTwo).length > 0) { | ||
77 | + for (let key in objectTwo) { | ||
78 | + if (objectTwo.hasOwnProperty(key) === true) { | ||
79 | + //数字值转为string类型,前后端加密规则保持一致 | ||
80 | + if(this.myIsNaN(objectTwo[key])){ | ||
81 | + objectTwo[key] = objectTwo[key].toString() | ||
82 | + } | ||
83 | + objectOne[key] = objectTwo[key]; | ||
84 | + } | ||
85 | + } | ||
86 | + } | ||
87 | + return objectOne; | ||
88 | + } | ||
89 | + | ||
90 | + static urlEncode(param, key, encode) { | ||
91 | + if (param == null) return ''; | ||
92 | + let paramStr = ''; | ||
93 | + let t = typeof (param); | ||
94 | + if (t == 'string' || t == 'number' || t == 'boolean') { | ||
95 | + paramStr += '&' + key + '=' + ((encode == null || encode) ? encodeURIComponent(param) : param); | ||
96 | + } else { | ||
97 | + for (let i in param) { | ||
98 | + let k = key == null ? i : key + (param instanceof Array ? '[' + i + ']' : '.' + i); | ||
99 | + paramStr += this.urlEncode(param[i], k, encode); | ||
100 | + } | ||
101 | + } | ||
102 | + return paramStr; | ||
103 | + }; | ||
104 | + | ||
105 | + static getDateTimeToString() { | ||
106 | + const date_ = new Date() | ||
107 | + const year = date_.getFullYear() | ||
108 | + let month = date_.getMonth() + 1 | ||
109 | + let day = date_.getDate() | ||
110 | + if (month < 10) month = '0' + month | ||
111 | + if (day < 10) day = '0' + day | ||
112 | + let hours = date_.getHours() | ||
113 | + let mins = date_.getMinutes() | ||
114 | + let secs = date_.getSeconds() | ||
115 | + const msecs = date_.getMilliseconds() | ||
116 | + if (hours < 10) hours = '0' + hours | ||
117 | + if (mins < 10) mins = '0' + mins | ||
118 | + if (secs < 10) secs = '0' + secs | ||
119 | + if (msecs < 10) secs = '0' + msecs | ||
120 | + return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs | ||
121 | + } | ||
122 | + // true:数值型的,false:非数值型 | ||
123 | + static myIsNaN(value) { | ||
124 | + return typeof value === 'number' && !isNaN(value); | ||
125 | + } | ||
126 | + | ||
127 | +} | ||
0 | \ No newline at end of file | 128 | \ No newline at end of file |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java
@@ -291,7 +291,7 @@ public class DateUtils extends PropertyEditorSupport { | @@ -291,7 +291,7 @@ public class DateUtils extends PropertyEditorSupport { | ||
291 | Date dt = new Date(); | 291 | Date dt = new Date(); |
292 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | 292 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
293 | String nowTime = df.format(dt); | 293 | String nowTime = df.format(dt); |
294 | - java.sql.Timestamp buydate = java.sql.Timestamp.valueOf(nowTime); | 294 | + Timestamp buydate = Timestamp.valueOf(nowTime); |
295 | return buydate; | 295 | return buydate; |
296 | } | 296 | } |
297 | 297 | ||
@@ -616,6 +616,10 @@ public class DateUtils extends PropertyEditorSupport { | @@ -616,6 +616,10 @@ public class DateUtils extends PropertyEditorSupport { | ||
616 | return 0; | 616 | return 0; |
617 | } | 617 | } |
618 | 618 | ||
619 | + public static Long getCurrentTimestamp() { | ||
620 | + return Long.valueOf(DateUtils.yyyymmddhhmmss.get().format(new Date())); | ||
621 | + } | ||
622 | + | ||
619 | /** | 623 | /** |
620 | * String类型 转换为Date, 如果参数长度为10 转换格式”yyyy-MM-dd“ 如果参数长度为19 转换格式”yyyy-MM-dd | 624 | * String类型 转换为Date, 如果参数长度为10 转换格式”yyyy-MM-dd“ 如果参数长度为19 转换格式”yyyy-MM-dd |
621 | * HH:mm:ss“ * @param text String类型的时间值 | 625 | * HH:mm:ss“ * @param text String类型的时间值 |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
0 → 100644
1 | +package org.jeecg.config.sign.interceptor; | ||
2 | + | ||
3 | +import org.springframework.context.annotation.Bean; | ||
4 | +import org.springframework.context.annotation.Configuration; | ||
5 | +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
6 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
7 | + | ||
8 | +/** | ||
9 | + * online 拦截器配置 | ||
10 | + */ | ||
11 | +@Configuration | ||
12 | +public class SignAuthConfiguration implements WebMvcConfigurer { | ||
13 | + | ||
14 | + @Bean | ||
15 | + public SignAuthInterceptor signAuthInterceptor() { | ||
16 | + return new SignAuthInterceptor(); | ||
17 | + } | ||
18 | + | ||
19 | + @Override | ||
20 | + 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); | ||
26 | + } | ||
27 | +} |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
0 → 100644
1 | +package org.jeecg.config.sign.interceptor; | ||
2 | + | ||
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 | + | ||
10 | +import org.jeecg.common.api.vo.Result; | ||
11 | +import org.jeecg.common.util.DateUtils; | ||
12 | +import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper; | ||
13 | +import org.jeecg.config.sign.util.HttpUtils; | ||
14 | +import org.jeecg.config.sign.util.SignUtil; | ||
15 | +import org.springframework.web.servlet.HandlerInterceptor; | ||
16 | + | ||
17 | +import com.alibaba.fastjson.JSON; | ||
18 | + | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | + | ||
21 | +/** | ||
22 | + * 签名拦截器 | ||
23 | + * @author qinfeng | ||
24 | + */ | ||
25 | +@Slf4j | ||
26 | +public class SignAuthInterceptor implements HandlerInterceptor { | ||
27 | + /** | ||
28 | + * 5分钟有效期 | ||
29 | + */ | ||
30 | + private final static long MAX_EXPIRE = 5 * 60; | ||
31 | + | ||
32 | + @Override | ||
33 | + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||
34 | + log.debug("request URI = " + request.getRequestURI()); | ||
35 | + HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request); | ||
36 | + //获取全部参数(包括URL和body上的) | ||
37 | + SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper); | ||
38 | + //对参数进行签名验证 | ||
39 | + String headerSign = request.getHeader("X-Sign"); | ||
40 | + String timesTamp = request.getHeader("X-TIMESTAMP"); | ||
41 | + | ||
42 | + //1.校验时间有消息 | ||
43 | + try { | ||
44 | + DateUtils.parseDate(timesTamp, "yyyyMMddHHmmss"); | ||
45 | + } catch (Exception e) { | ||
46 | + throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP格式必须为:yyyyMMddHHmmss"); | ||
47 | + } | ||
48 | + Long clientTimestamp = Long.parseLong(timesTamp); | ||
49 | + //判断时间戳 timestamp=201808091113 | ||
50 | + if ((DateUtils.getCurrentTimestamp() - clientTimestamp) > MAX_EXPIRE) { | ||
51 | + throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP已过期"); | ||
52 | + } | ||
53 | + | ||
54 | + //2.校验签名 | ||
55 | + boolean isSigned = SignUtil.verifySign(allParams,headerSign); | ||
56 | + | ||
57 | + if (isSigned) { | ||
58 | + log.debug("Sign 签名通过!Header Sign : {}",headerSign); | ||
59 | + return true; | ||
60 | + } else { | ||
61 | + log.error("request URI = " + request.getRequestURI()); | ||
62 | + 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 | + //校验失败返回前端 | ||
73 | + response.setCharacterEncoding("UTF-8"); | ||
74 | + response.setContentType("application/json; charset=utf-8"); | ||
75 | + PrintWriter out = response.getWriter(); | ||
76 | + Result<?> result = Result.error("Sign签名校验失败!"); | ||
77 | + out.print(JSON.toJSON(result)); | ||
78 | + return false; | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | +} |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java
0 → 100644
1 | +package org.jeecg.config.sign.util; | ||
2 | + | ||
3 | +import javax.servlet.ReadListener; | ||
4 | +import javax.servlet.ServletInputStream; | ||
5 | +import javax.servlet.ServletRequest; | ||
6 | +import javax.servlet.http.HttpServletRequest; | ||
7 | +import javax.servlet.http.HttpServletRequestWrapper; | ||
8 | +import java.io.*; | ||
9 | +import java.nio.charset.Charset; | ||
10 | + | ||
11 | +/** | ||
12 | + * 保存过滤器里面的流 | ||
13 | + * | ||
14 | + * @author show | ||
15 | + * @date 10:03 2019/5/30 | ||
16 | + */ | ||
17 | +public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { | ||
18 | + | ||
19 | + private final byte[] body; | ||
20 | + | ||
21 | + public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) { | ||
22 | + | ||
23 | + super(request); | ||
24 | + String sessionStream = getBodyString(request); | ||
25 | + body = sessionStream.getBytes(Charset.forName("UTF-8")); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 获取请求Body | ||
30 | + * | ||
31 | + * @param request | ||
32 | + * @return | ||
33 | + */ | ||
34 | + public String getBodyString(final ServletRequest request) { | ||
35 | + | ||
36 | + StringBuilder sb = new StringBuilder(); | ||
37 | + try (InputStream inputStream = cloneInputStream(request.getInputStream()); | ||
38 | + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")))) { | ||
39 | + String line; | ||
40 | + while ((line = reader.readLine()) != null) { | ||
41 | + sb.append(line); | ||
42 | + } | ||
43 | + } catch (IOException e) { | ||
44 | + e.printStackTrace(); | ||
45 | + } | ||
46 | + return sb.toString(); | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * Description: 复制输入流</br> | ||
51 | + * | ||
52 | + * @param inputStream | ||
53 | + * @return</br> | ||
54 | + */ | ||
55 | + public InputStream cloneInputStream(ServletInputStream inputStream) { | ||
56 | + | ||
57 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | ||
58 | + byte[] buffer = new byte[1024]; | ||
59 | + int len; | ||
60 | + try { | ||
61 | + while ((len = inputStream.read(buffer)) > -1) { | ||
62 | + byteArrayOutputStream.write(buffer, 0, len); | ||
63 | + } | ||
64 | + byteArrayOutputStream.flush(); | ||
65 | + } catch (IOException e) { | ||
66 | + e.printStackTrace(); | ||
67 | + } | ||
68 | + return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public BufferedReader getReader() { | ||
73 | + | ||
74 | + return new BufferedReader(new InputStreamReader(getInputStream())); | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public ServletInputStream getInputStream() { | ||
79 | + | ||
80 | + final ByteArrayInputStream bais = new ByteArrayInputStream(body); | ||
81 | + return new ServletInputStream() { | ||
82 | + | ||
83 | + @Override | ||
84 | + public int read() { | ||
85 | + | ||
86 | + return bais.read(); | ||
87 | + } | ||
88 | + | ||
89 | + @Override | ||
90 | + public boolean isFinished() { | ||
91 | + | ||
92 | + return false; | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public boolean isReady() { | ||
97 | + | ||
98 | + return false; | ||
99 | + } | ||
100 | + | ||
101 | + @Override | ||
102 | + public void setReadListener(ReadListener readListener) { | ||
103 | + | ||
104 | + } | ||
105 | + }; | ||
106 | + } | ||
107 | +} | ||
0 | \ No newline at end of file | 108 | \ No newline at end of file |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java
0 → 100644
1 | +package org.jeecg.config.sign.util; | ||
2 | + | ||
3 | +import java.io.BufferedReader; | ||
4 | +import java.io.IOException; | ||
5 | +import java.io.InputStreamReader; | ||
6 | +import java.io.UnsupportedEncodingException; | ||
7 | +import java.net.URLDecoder; | ||
8 | +import java.util.HashMap; | ||
9 | +import java.util.Map; | ||
10 | +import java.util.SortedMap; | ||
11 | +import java.util.TreeMap; | ||
12 | + | ||
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 | +/** | ||
21 | + * http 工具类 获取请求中的参数 | ||
22 | + * | ||
23 | + * @author show | ||
24 | + * @date 14:23 2019/5/29 | ||
25 | + */ | ||
26 | +public class HttpUtils { | ||
27 | + | ||
28 | + /** | ||
29 | + * 将URL的参数和body参数合并 | ||
30 | + * | ||
31 | + * @author show | ||
32 | + * @date 14:24 2019/5/29 | ||
33 | + * @param request | ||
34 | + */ | ||
35 | + public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException { | ||
36 | + | ||
37 | + SortedMap<String, String> result = new TreeMap<>(); | ||
38 | + // 获取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); | ||
42 | + } | ||
43 | + // 获取URL上的参数 | ||
44 | + Map<String, String> urlParams = getUrlParams(request); | ||
45 | + for (Map.Entry entry : urlParams.entrySet()) { | ||
46 | + result.put((String)entry.getKey(), (String)entry.getValue()); | ||
47 | + } | ||
48 | + Map<String, String> allRequestParam = new HashMap<>(16); | ||
49 | + // get请求不需要拿body参数 | ||
50 | + if (!HttpMethod.GET.name().equals(request.getMethod())) { | ||
51 | + allRequestParam = getAllRequestParam(request); | ||
52 | + } | ||
53 | + // 将URL的参数和body参数进行合并 | ||
54 | + if (allRequestParam != null) { | ||
55 | + for (Map.Entry entry : allRequestParam.entrySet()) { | ||
56 | + result.put((String)entry.getKey(), (String)entry.getValue()); | ||
57 | + } | ||
58 | + } | ||
59 | + return result; | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * 获取 Body 参数 | ||
64 | + * | ||
65 | + * @author show | ||
66 | + * @date 15:04 2019/5/30 | ||
67 | + * @param request | ||
68 | + */ | ||
69 | + public static Map<String, String> getAllRequestParam(final HttpServletRequest request) throws IOException { | ||
70 | + | ||
71 | + BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); | ||
72 | + String str = ""; | ||
73 | + StringBuilder wholeStr = new StringBuilder(); | ||
74 | + // 一行一行的读取body体里面的内容; | ||
75 | + while ((str = reader.readLine()) != null) { | ||
76 | + wholeStr.append(str); | ||
77 | + } | ||
78 | + // 转化成json对象 | ||
79 | + return JSONObject.parseObject(wholeStr.toString(), Map.class); | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * 将URL请求参数转换成Map | ||
84 | + * | ||
85 | + * @author show | ||
86 | + * @param request | ||
87 | + */ | ||
88 | + public static Map<String, String> getUrlParams(HttpServletRequest request) { | ||
89 | + Map<String, String> result = new HashMap<>(16); | ||
90 | + if(oConvertUtils.isEmpty(request.getQueryString())){ | ||
91 | + return result; | ||
92 | + } | ||
93 | + String param = ""; | ||
94 | + try { | ||
95 | + param = URLDecoder.decode(request.getQueryString(), "utf-8"); | ||
96 | + } catch (UnsupportedEncodingException e) { | ||
97 | + e.printStackTrace(); | ||
98 | + } | ||
99 | + String[] params = param.split("&"); | ||
100 | + for (String s : params) { | ||
101 | + int index = s.indexOf("="); | ||
102 | + result.put(s.substring(0, index), s.substring(index + 1)); | ||
103 | + } | ||
104 | + return result; | ||
105 | + } | ||
106 | +} | ||
0 | \ No newline at end of file | 107 | \ No newline at end of file |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
0 → 100644
1 | +package org.jeecg.config.sign.util; | ||
2 | + | ||
3 | +import com.alibaba.fastjson.JSONObject; | ||
4 | +import lombok.extern.slf4j.Slf4j; | ||
5 | +import org.springframework.util.DigestUtils; | ||
6 | +import org.springframework.util.StringUtils; | ||
7 | + | ||
8 | +import java.util.SortedMap; | ||
9 | + | ||
10 | +/** | ||
11 | + * 签名工具类 | ||
12 | + * | ||
13 | + * @author show | ||
14 | + * @date 10:01 2019/5/30 | ||
15 | + */ | ||
16 | +@Slf4j | ||
17 | +public class SignUtil { | ||
18 | + //签名密钥串(前后端要一致,正式发布请自行修改) | ||
19 | + private static final String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | ||
20 | + public static final String xPathVariable = "x-path-variable"; | ||
21 | + | ||
22 | + /** | ||
23 | + * @param params | ||
24 | + * 所有的请求参数都会在这里进行排序加密 | ||
25 | + * @return 验证签名结果 | ||
26 | + */ | ||
27 | + public static boolean verifySign(SortedMap<String, String> params,String headerSign) { | ||
28 | + if (params == null || StringUtils.isEmpty(headerSign)) { | ||
29 | + return false; | ||
30 | + } | ||
31 | + // 把参数加密 | ||
32 | + String paramsSign = getParamsSign(params); | ||
33 | + log.info("Param Sign : {}", paramsSign); | ||
34 | + return !StringUtils.isEmpty(paramsSign) && headerSign.equals(paramsSign); | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * @param params | ||
39 | + * 所有的请求参数都会在这里进行排序加密 | ||
40 | + * @return 得到签名 | ||
41 | + */ | ||
42 | + public static String getParamsSign(SortedMap<String, String> params) { | ||
43 | + //去掉 Url 里的时间戳 | ||
44 | + params.remove("_t"); | ||
45 | + String paramsJsonStr = JSONObject.toJSONString(params); | ||
46 | + log.info("Param paramsJsonStr : {}", paramsJsonStr); | ||
47 | + return DigestUtils.md5DigestAsHex((paramsJsonStr+signatureSecret).getBytes()).toUpperCase(); | ||
48 | + } | ||
49 | +} | ||
0 | \ No newline at end of file | 50 | \ No newline at end of file |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java
1 | package org.jeecg.config.init; | 1 | package org.jeecg.config.init; |
2 | 2 | ||
3 | +import com.alibaba.druid.filter.config.ConfigTools; | ||
3 | import lombok.extern.slf4j.Slf4j; | 4 | import lombok.extern.slf4j.Slf4j; |
4 | import org.apache.commons.lang3.StringUtils; | 5 | import org.apache.commons.lang3.StringUtils; |
5 | import org.jeecgframework.codegenerate.database.CodegenDatasourceConfig; | 6 | import org.jeecgframework.codegenerate.database.CodegenDatasourceConfig; |
@@ -25,11 +26,21 @@ public class CodeGenerateDbConfig { | @@ -25,11 +26,21 @@ public class CodeGenerateDbConfig { | ||
25 | private String password; | 26 | private String password; |
26 | @Value("${spring.datasource.dynamic.datasource.master.driver-class-name:}") | 27 | @Value("${spring.datasource.dynamic.datasource.master.driver-class-name:}") |
27 | private String driverClassName; | 28 | private String driverClassName; |
29 | + @Value("${spring.datasource.dynamic.datasource.master.druid.public-key:}") | ||
30 | + private String publicKey; | ||
28 | 31 | ||
29 | 32 | ||
30 | @Bean | 33 | @Bean |
31 | public CodeGenerateDbConfig initCodeGenerateDbConfig() { | 34 | public CodeGenerateDbConfig initCodeGenerateDbConfig() { |
32 | if(StringUtils.isNotBlank(url)){ | 35 | if(StringUtils.isNotBlank(url)){ |
36 | + if(StringUtils.isNotBlank(publicKey)){ | ||
37 | + try { | ||
38 | + password = ConfigTools.decrypt(publicKey, password); | ||
39 | + } catch (Exception e) { | ||
40 | + e.printStackTrace(); | ||
41 | + log.error(" 代码生成器数据库连接,数据库密码解密失败!"); | ||
42 | + } | ||
43 | + } | ||
33 | CodegenDatasourceConfig.initDbConfig(driverClassName,url, username, password); | 44 | CodegenDatasourceConfig.initDbConfig(driverClassName,url, username, password); |
34 | log.info(" 代码生成器数据库连接,使用application.yml的DB配置 ###################"); | 45 | log.info(" 代码生成器数据库连接,使用application.yml的DB配置 ###################"); |
35 | } | 46 | } |
jeecg-boot/pom.xml
@@ -39,7 +39,7 @@ | @@ -39,7 +39,7 @@ | ||
39 | <shiro.version>1.7.1</shiro.version> | 39 | <shiro.version>1.7.1</shiro.version> |
40 | <java-jwt.version>3.11.0</java-jwt.version> | 40 | <java-jwt.version>3.11.0</java-jwt.version> |
41 | <shiro-redis.version>3.1.0</shiro-redis.version> | 41 | <shiro-redis.version>3.1.0</shiro-redis.version> |
42 | - <codegenerate.version>1.3.2</codegenerate.version> | 42 | + <codegenerate.version>1.3.3</codegenerate.version> |
43 | <autopoi-web.version>1.3.2</autopoi-web.version> | 43 | <autopoi-web.version>1.3.2</autopoi-web.version> |
44 | <minio.version>8.0.3</minio.version> | 44 | <minio.version>8.0.3</minio.version> |
45 | <justauth-spring-boot-starter.version>1.3.4</justauth-spring-boot-starter.version> | 45 | <justauth-spring-boot-starter.version>1.3.4</justauth-spring-boot-starter.version> |