签名规则
1、线下分配appid和appsecret,针对不同的调用方分配不同的appid和appsecret
2、加入timestamp(时间戳),10分钟内数据有效
3、加入流水号nonce(防止重复提交),至少为10位。
4、加入signature,所有数据的签名信息。
1.pom
<!--DigestUtils依赖-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
2.签名生成工具类
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class SignUtils {
private SignUtils() {
}
public static String getTimestamp() {
//生成时间戳
long timestampLong = System.currentTimeMillis();
String timestampStr = String.valueOf(timestampLong);
return timestampStr;
}
public static String getNonceStr(int length) {
//生成随机字符串
String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
Random random = new Random();
StringBuffer randomStr = new StringBuffer();
// 设置生成字符串的长度,用于循环
for (int i = 0; i < length; ++i) {
//从62个的数字或字母中选择
int number = random.nextInt(62);
//将产生的数字通过length次承载到sb中
randomStr.append(str.charAt(number));
}
//将承载的字符转换成字符串
return randomStr.toString();
}
/*
* @Date 2021/6/30 11:21
* @Param [params, privateKey 私钥]
* @Return java.lang.String
* @Desc 签名生成方法
*
*/
public static String createSign(Map<String, String> params, String privateKey) {
StringBuilder sb = new StringBuilder();
// 将参数以参数名的字典升序排序
Map<String, String> sortParams = new TreeMap<String, String>(params);
// 遍历排序的字典,并拼接"key=value"格式
for (Map.Entry<String, String> entry : sortParams.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().trim();
if (!StringUtils.isEmpty(value))
sb.append("&").append(key).append("=").append(value);
}
String stringA = sb.toString().replaceFirst("&", "");
// String privateKey = "WHJBK24NXCX"; //私钥最后放在配置文件里面读取
String stringSignTemp = stringA + "&" + "appkey=" + privateKey;
//将签名使用MD5加密并全部字母变为大写
// String signValue = Md5Encrypt.md5(stringSignTemp).toUpperCase();
String signValue = DigestUtils.md5Hex(stringSignTemp+ getTimestamp());
System.out.println("stringA+privateKey后MD5加密+转换全部大写生成sign为: " + signValue);
return signValue;
}
public static void main(String[] args) {
Map<String, String> params = new HashMap<>();
params.put("getNonceStr",getNonceStr(1024));
SignUtils.createSign(params, "@@@@@@@```11");
// System.out.println(SignUtils.getNonceStr(11));
}
需要的jar包
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
生成相关的key
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
public class AccessKeyUtil {
private static final String ALGORITHM_MD5 = "md5";
private static final String CHARSET = "UTF-8";
private static final String ALGORITHM_HMACSHA256 = "HmacSHA256";
private AccessKeyUtil() {
}
/**
* 生成签名
*
* @param obj
* @param secretKey
* @return
*/
public static String generateSignature(Object obj, String secretKey) {
String jsonString = JSONObject.toJSONString(obj, SerializerFeature.SortField);
return encrypt(jsonString, secretKey);
}
/**
* 编码
*
* @param encodeString
* @param secretKey
* @return
*/
private static String encrypt(String encodeString, String secretKey) {
try {
Mac mac = Mac.getInstance(ALGORITHM_HMACSHA256);
mac.init(new SecretKeySpec(secretKey.getBytes(), ALGORITHM_HMACSHA256));
byte[] cryToGraph = mac.doFinal(encodeString.getBytes(CHARSET));
//通过Base64编码为ASCII字符后传输
return Base64.encodeBase64String(cryToGraph);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成SecretKey
*
* @param key
* @return
*/
public static String generateSecretKey(String key) {
return getAESKeyBytes(key);
}
/**
* 生成AccessKey
*
* @param key
* @return
*/
public static String generateAccessKey(String key) {
return getAESKeyBytes(key);
}
/**
* 根据字符串生成AES的密钥字节数组<br>
*/
private static String getAESKeyBytes(String key) {
try {
MessageDigest md = MessageDigest.getInstance(ALGORITHM_MD5);
md.update(key.getBytes(CHARSET));
byte[] md5Bytes = md.digest();
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
public static synchronized Long generate() {
Long time = (new Date()).getTime();
String timeStr = Long.toString(time);
int length = timeStr.length();
Random random = new Random();
int lastStr = (int) ((double) random.nextFloat() * Math.pow(10.0D, (double) (16 - length)));
Long id = Long.parseLong(timeStr + lastStr);
return id;
}
public static String generateString(String prefix) {
return prefix + UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* @Desc 生成appkey
* @Param [key] 参数
*/
public static String generateAppKey(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
StringBuilder builder = new StringBuilder();
builder.append(key);
builder.append(":");
builder.append(AccessKeyUtil.generateString(""));
String appKey = builder.toString();
return DigestUtils.md5Hex(appKey);
}
public static void main(String[] args) {
String appKey = AccessKeyUtil.generateAppKey("123");
String accessKey = AccessKeyUtil.generateAccessKey("123");
String secretKey = AccessKeyUtil.generateSecretKey("123" + ":secretKey");
System.out.println("appKey--->" + appKey);
System.out.println("accessKey--->" + accessKey);
System.out.println("secretKey--->" + secretKey);
}
}
sign生成一般 appId或请求参数+appKey+accessKey+secretKey+请求时的时间戳
sign 由DigestUtils.md5Hex(appKey+accessKey+ secretKey+ timestamp ) 生成