|
|
@ -1,9 +1,11 @@ |
|
|
|
package com.yxt.ss.gateway.api.rest; |
|
|
|
|
|
|
|
import com.yxt.ss.gateway.api.utils.ResultBean; |
|
|
|
import com.yxt.ss.gateway.api.utils.SignatureQuery; |
|
|
|
import com.yxt.ss.gateway.api.utils.SignatureUtil; |
|
|
|
import com.fasterxml.jackson.databind.JsonNode; |
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import com.yxt.ss.gateway.api.utils.*; |
|
|
|
import okhttp3.*; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.beans.factory.annotation.Value; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.web.bind.annotation.PostMapping; |
|
|
|
import org.springframework.web.bind.annotation.RequestMapping; |
|
|
@ -15,6 +17,7 @@ import java.io.UnsupportedEncodingException; |
|
|
|
import java.net.URLEncoder; |
|
|
|
import java.security.MessageDigest; |
|
|
|
import java.security.NoSuchAlgorithmException; |
|
|
|
import java.time.Instant; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.TreeMap; |
|
|
@ -29,26 +32,42 @@ import java.util.concurrent.TimeUnit; |
|
|
|
@RequestMapping("/signature") |
|
|
|
public class Signature { |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private AppKeyConfig appKeyConfig; |
|
|
|
|
|
|
|
public String getSecret(String appKey) { |
|
|
|
return appKeyConfig.getKeys().get(appKey); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//appkey
|
|
|
|
static final String APPKEY = "appkey"; |
|
|
|
static final String APPKEY = "appKey4"; |
|
|
|
//secret
|
|
|
|
static final String SECRET = "secret"; |
|
|
|
|
|
|
|
//获取签名
|
|
|
|
//获取参数
|
|
|
|
@PostMapping("/getSign") |
|
|
|
ResultBean<String> getSign(SignatureQuery query) { |
|
|
|
ResultBean getSign(SignatureQuery query) { |
|
|
|
ResultBean<String> rb = ResultBean.fireFail(); |
|
|
|
try { |
|
|
|
Map<String, String> formData = new HashMap<>(); |
|
|
|
// Map<String, String> map = query.getParameters();
|
|
|
|
// formData.put("key1", map.getOrDefault("key1", "").toString());
|
|
|
|
formData = query.getParameters(); |
|
|
|
String appKey = query.getAppKey(); |
|
|
|
String secret = query.getSecret(); |
|
|
|
|
|
|
|
Map<String, String> formData = query.getParameters(); |
|
|
|
Map<String, String> tree = new TreeMap<>(formData); |
|
|
|
tree.put("_app", APPKEY); |
|
|
|
tree.put("_t", String.valueOf(System.currentTimeMillis() / 1000)); |
|
|
|
tree.put("_s", ""); |
|
|
|
// 生成签名
|
|
|
|
String sign = SignatureUtil.generateSignature(formData, appKey, secret); |
|
|
|
return rb.success().setData(sign); |
|
|
|
String sign = SignatureUtil.generateSignature(tree, SECRET); |
|
|
|
//添加签名值map
|
|
|
|
tree.put("_sign", sign); |
|
|
|
//发起请求
|
|
|
|
ResultBean resultBean = client(tree); |
|
|
|
if (!resultBean.getSuccess()) { |
|
|
|
return rb.setMsg(resultBean.getMsg()); |
|
|
|
} |
|
|
|
//通过验证继续调用接口
|
|
|
|
|
|
|
|
|
|
|
|
return rb.success(); |
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
return rb.setMsg("Unsupported encoding: " + e.getMessage()); |
|
|
|
} catch (NoSuchAlgorithmException e) { |
|
|
@ -56,7 +75,71 @@ public class Signature { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static void main(String[] args) { |
|
|
|
//验证
|
|
|
|
@PostMapping("/validate") |
|
|
|
ResultBean validate(Map<String, String> data) { |
|
|
|
ResultBean rb = ResultBean.fireFail(); |
|
|
|
Map<String, String> parameters = data; |
|
|
|
//1、解析参数,校验_app是否正确,_t是否在5分钟内。
|
|
|
|
if (!parameters.containsKey("_app") || |
|
|
|
parameters.get("_app") == null || |
|
|
|
parameters.get("_app").trim().isEmpty()) { |
|
|
|
return rb.setMsg("_app参数缺失或无效"); |
|
|
|
} |
|
|
|
//2、根据_app参数获取对应的secret值。
|
|
|
|
String secret = getSecret(parameters.get("_app")); |
|
|
|
if (StringUtils.isEmpty(secret)) { |
|
|
|
return rb.setMsg("_app参数不正确"); |
|
|
|
} |
|
|
|
if (parameters.containsKey("_t") || |
|
|
|
parameters.get("_t") == null || |
|
|
|
parameters.get("_t").trim().isEmpty()) { |
|
|
|
return rb.setMsg("_t参数缺失"); |
|
|
|
} |
|
|
|
|
|
|
|
String _t = parameters.get("_t"); |
|
|
|
// 获取当前的秒级时间戳
|
|
|
|
long currentTimestamp = Instant.now().getEpochSecond(); |
|
|
|
// 将字符串转换为 long 类型
|
|
|
|
long timestamp = Long.parseLong(_t); |
|
|
|
// 计算时间差,允许最大偏差 5 分钟(300秒)
|
|
|
|
long timeDifference = Math.abs(currentTimestamp - timestamp); |
|
|
|
|
|
|
|
if (timeDifference > 300) { |
|
|
|
return rb.setMsg("时间已超过5分钟,时间失效"); |
|
|
|
} |
|
|
|
String _sign = parameters.get("_sign"); |
|
|
|
//3、检验签名,成功则继续调用接口,失败返回失败信息。
|
|
|
|
parameters.remove("_sign"); |
|
|
|
try { |
|
|
|
// 3.1. 重新生成签名
|
|
|
|
String calculatedSignature = SignatureUtil.generateSignature(parameters, secret); |
|
|
|
|
|
|
|
// 3.2. 使用固定时间比较方式验证签名
|
|
|
|
boolean valid = MessageDigest.isEqual( |
|
|
|
calculatedSignature.getBytes("UTF-8"), |
|
|
|
_sign.getBytes("UTF-8") |
|
|
|
); |
|
|
|
if (!valid) { |
|
|
|
return rb.setMsg("签名不正确"); |
|
|
|
} |
|
|
|
|
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
return rb.setMsg("Encoding error: " + e.getMessage()); |
|
|
|
} catch (NoSuchAlgorithmException e) { |
|
|
|
return rb.setMsg("Algorithm error: " + e.getMessage()); |
|
|
|
} catch (Exception e) { |
|
|
|
return rb.setMsg("Unexpected error: " + e.getMessage()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return rb.success(); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
public ResultBean client(Map<String, String> data) { |
|
|
|
ResultBean rb = ResultBean.fireFail(); |
|
|
|
OkHttpClient client = new OkHttpClient.Builder() |
|
|
|
.connectTimeout(10, TimeUnit.SECONDS) |
|
|
|
.writeTimeout(10, TimeUnit.SECONDS) |
|
|
@ -66,14 +149,7 @@ public class Signature { |
|
|
|
try { |
|
|
|
// 构建URL
|
|
|
|
String endPoint = "http://127.0.0.1:9999"; |
|
|
|
String path = "/signature/getSign"; |
|
|
|
|
|
|
|
// 假设data是一个包含所有参数的字典
|
|
|
|
Map<String, String> data = new HashMap<>(); |
|
|
|
data.put("parameters[key1]", "value1"); |
|
|
|
data.put("parameters[key2]", "value2"); |
|
|
|
data.put("appKey", "testAppKey"); |
|
|
|
data.put("secret", "testSecret"); |
|
|
|
String path = "/signature/validate"; |
|
|
|
|
|
|
|
// 创建FormData
|
|
|
|
FormBody.Builder formBuilder = new FormBody.Builder(); |
|
|
@ -94,93 +170,28 @@ public class Signature { |
|
|
|
|
|
|
|
// 发送请求
|
|
|
|
try (Response response = client.newCall(request).execute()) { |
|
|
|
String responseBody = response.body().string(); |
|
|
|
// 使用 Jackson 解析 JSON 响应
|
|
|
|
ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
JsonNode jsonNode = objectMapper.readTree(responseBody); |
|
|
|
String success = jsonNode.path("success").asText(); |
|
|
|
String msg = jsonNode.path("msg").asText(); |
|
|
|
if ("false".equals(success)) { |
|
|
|
return rb.setMsg(msg); |
|
|
|
} |
|
|
|
if (response.isSuccessful()) { |
|
|
|
System.out.println("Response: " + response.body().string()); |
|
|
|
} else { |
|
|
|
System.err.println("Request failed: " + response.code()); |
|
|
|
System.err.println("Request failed: " + response.message()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} catch (IOException e) { |
|
|
|
System.err.println("Network error: " + e.getMessage()); |
|
|
|
} catch (Exception e) { |
|
|
|
System.err.println("Unexpected error: " + e.getMessage()); |
|
|
|
} |
|
|
|
return rb.success(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 对传入的参数集合进行签名处理 |
|
|
|
* 返回系统参数 |
|
|
|
*/ |
|
|
|
@PostMapping("/getSignParameters") |
|
|
|
public ResultBean<Map<String, String>> signParameters(SignatureQuery query) { |
|
|
|
ResultBean<Map<String, String>> rb = ResultBean.fireFail(); |
|
|
|
|
|
|
|
try { |
|
|
|
Map<String, String> parameters = query.getParameters(); |
|
|
|
|
|
|
|
// 2. 使用 TreeMap 按照字典顺序对参数进行排序
|
|
|
|
Map<String, String> tree = new TreeMap<>(parameters); |
|
|
|
tree.put("_app", query.getAppKey()); |
|
|
|
tree.putIfAbsent("_t", String.valueOf(System.currentTimeMillis())); |
|
|
|
|
|
|
|
// 3. 拼接参数串
|
|
|
|
String content = SignatureUtil.joinParameters(tree); |
|
|
|
|
|
|
|
// 4. 将参数串前后拼接密钥
|
|
|
|
content = query.getSecret() + content + query.getSecret(); |
|
|
|
|
|
|
|
// 5. 计算 sign 值
|
|
|
|
String sign = SignatureUtil.md5(content); |
|
|
|
|
|
|
|
// 6. 添加系统参数
|
|
|
|
tree.put("_sign", sign); |
|
|
|
tree.put("_s", ""); |
|
|
|
|
|
|
|
return rb.success().setData(tree); |
|
|
|
|
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
return rb.setMsg("Encoding error: " + e.getMessage()); |
|
|
|
} catch (NoSuchAlgorithmException e) { |
|
|
|
return rb.setMsg("Algorithm error: " + e.getMessage()); |
|
|
|
} catch (Exception e) { |
|
|
|
return rb.setMsg("Unexpected error: " + e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 验证签名是否正确 |
|
|
|
* |
|
|
|
* @return 是否验证通过 |
|
|
|
*/ |
|
|
|
@PostMapping("/validateSignature") |
|
|
|
public ResultBean<Boolean> validateSignature(SignatureQuery query) { |
|
|
|
ResultBean<Boolean> rb = ResultBean.fireFail(); |
|
|
|
|
|
|
|
try { |
|
|
|
Map<String, String> parameters = query.getParameters(); |
|
|
|
String appKey = query.getAppKey(); |
|
|
|
String secret = query.getSecret(); |
|
|
|
|
|
|
|
|
|
|
|
// 2. 重新生成签名
|
|
|
|
String calculatedSignature = SignatureUtil.generateSignature(parameters, appKey, secret); |
|
|
|
|
|
|
|
// 3. 使用固定时间比较方式验证签名
|
|
|
|
boolean valid = MessageDigest.isEqual( |
|
|
|
calculatedSignature.getBytes("UTF-8"), |
|
|
|
query.getReceivedSignature().getBytes("UTF-8") |
|
|
|
); |
|
|
|
|
|
|
|
return rb.success().setData(valid); |
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
return rb.setMsg("Encoding error: " + e.getMessage()); |
|
|
|
} catch (NoSuchAlgorithmException e) { |
|
|
|
return rb.setMsg("Algorithm error: " + e.getMessage()); |
|
|
|
} catch (Exception e) { |
|
|
|
return rb.setMsg("Unexpected error: " + e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|