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 | 1 | import Vue from 'vue' |
2 | 2 | import { axios } from '@/utils/request' |
3 | +import signMd5Utils from '@/utils/encryption/signMd5Utils' | |
3 | 4 | |
4 | 5 | const api = { |
5 | 6 | user: '/mock/api/user', |
... | ... | @@ -13,19 +14,29 @@ export default api |
13 | 14 | |
14 | 15 | //post |
15 | 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 | 21 | return axios({ |
17 | 22 | url: url, |
18 | 23 | method:'post' , |
19 | - data: parameter | |
24 | + data: parameter, | |
25 | + headers: signHeader | |
20 | 26 | }) |
21 | 27 | } |
22 | 28 | |
23 | 29 | //post method= {post | put} |
24 | 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 | 35 | return axios({ |
26 | 36 | url: url, |
27 | 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 | 51 | |
41 | 52 | //get |
42 | 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 | 58 | return axios({ |
44 | 59 | url: url, |
45 | 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 | 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 | 291 | Date dt = new Date(); |
292 | 292 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
293 | 293 | String nowTime = df.format(dt); |
294 | - java.sql.Timestamp buydate = java.sql.Timestamp.valueOf(nowTime); | |
294 | + Timestamp buydate = Timestamp.valueOf(nowTime); | |
295 | 295 | return buydate; |
296 | 296 | } |
297 | 297 | |
... | ... | @@ -616,6 +616,10 @@ public class DateUtils extends PropertyEditorSupport { |
616 | 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 | 624 | * String类型 转换为Date, 如果参数长度为10 转换格式”yyyy-MM-dd“ 如果参数长度为19 转换格式”yyyy-MM-dd |
621 | 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 | 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 | 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 | 50 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java
1 | 1 | package org.jeecg.config.init; |
2 | 2 | |
3 | +import com.alibaba.druid.filter.config.ConfigTools; | |
3 | 4 | import lombok.extern.slf4j.Slf4j; |
4 | 5 | import org.apache.commons.lang3.StringUtils; |
5 | 6 | import org.jeecgframework.codegenerate.database.CodegenDatasourceConfig; |
... | ... | @@ -25,11 +26,21 @@ public class CodeGenerateDbConfig { |
25 | 26 | private String password; |
26 | 27 | @Value("${spring.datasource.dynamic.datasource.master.driver-class-name:}") |
27 | 28 | private String driverClassName; |
29 | + @Value("${spring.datasource.dynamic.datasource.master.druid.public-key:}") | |
30 | + private String publicKey; | |
28 | 31 | |
29 | 32 | |
30 | 33 | @Bean |
31 | 34 | public CodeGenerateDbConfig initCodeGenerateDbConfig() { |
32 | 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 | 44 | CodegenDatasourceConfig.initDbConfig(driverClassName,url, username, password); |
34 | 45 | log.info(" 代码生成器数据库连接,使用application.yml的DB配置 ###################"); |
35 | 46 | } |
... | ... |
jeecg-boot/pom.xml
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | <shiro.version>1.7.1</shiro.version> |
40 | 40 | <java-jwt.version>3.11.0</java-jwt.version> |
41 | 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 | 43 | <autopoi-web.version>1.3.2</autopoi-web.version> |
44 | 44 | <minio.version>8.0.3</minio.version> |
45 | 45 | <justauth-spring-boot-starter.version>1.3.4</justauth-spring-boot-starter.version> |
... | ... |