最近工作中,在开发app端接口的时候,app端调用后端服务接口的时候,一直报签名错误。这里介绍一下前后端生成签名的大概流程。
所以需要明白的几点:
1、前后端签名我们项目采用的md5的加密方法。 具体方法可以看下面代码。当然还可以有其他的好多的加密方法。这只是其中一种。
2、前端和后端将数据生成对应的sign必须采用相同的规则,生成对应的字符串,然后进行md5加密,这样生成的sign才能相同。如果数据被拦截,修改其中任意一点数据,都会造成前后端数据不一致,从而导致生成的sign不一致。
3、一般小的项目验证签名在后端会添加到一个拦截器里面。只要app端调用都会进行拦截验证。正常的大项目,肯定一般会在网关层进行拦截验证。
以下是我模拟的我们一个生成sign的验证流程,希望对你有帮助,代码走起。
public class Test {
public static void main(String[] args) {
//map 前台传过来的参数,其中sign是前台数据经过md5加密之后,生成的sign标识
Map<String,String> map = new HashMap<>();
map.put("name","hxx");
map.put("age","20");
map.put("sex","");
map.put("email","xxx@qq.com");
map.put("sign","7876850823c9c0d3c2c411a9693b36ff");
//后台需要根据前台传过来的参数(map),生成新的签名,此时必须排除前台生成的sign参数
List<String> exludeKey = new ArrayList<>();
exludeKey.add("sign");
// 为了增加安全性,前后台可以增加一个密钥,前后端在加密的时候将此密钥增加到md5加密里面(此密钥可以配置到共享配置中心,后面可以随时变化)
String bindKey = "bindKey";
String secretKey = "123456qwerty";
//生成新的签名
String signResult = sign(map,secretKey,bindKey,exludeKey);
if(signResult.equals(map.get("sign"))){
System.out.println(true);
}else{
System.out.println(false);
}
}
/**
* MD5加密字符串
* @param str
* @return
*/
public static String encryptToMD5(String str) {
System.out.println("md5加密前数据...."+str);
String result = DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
System.out.println("md5加密后数据...."+result);
return result;
}
/**
* 生成新的签名
* @param map 前端传过来的参数
* @param bindKey 前端和后端共同增加约定key
* @param secretKey 前端和后端共同增加约定value(共享配置中心可以随时变化)
* @param exludeKey 排除前端传过来的sign签名字段
* @return
*/
public static String sign(Map<String,String> map,String bindKey,String secretKey,List<String> exludeKey){
List<String> sortList = new ArrayList();
// 前台穿过的参数,过滤空、null、sign。获取对应的key,并且对key进行排序(排序的目的是为了前端和后端保持相同的规则,然后生成相同字符串,这样生成的sign才能相同)
for(Map.Entry entry: map.entrySet()){
String value = entry.getValue() + "";
if(null != value && !"".equals(value)&& !exludeKey.contains(entry.getKey())){
sortList.add((String) entry.getKey());
}
}
//对key进行排序
Collections.sort(sortList);
StringBuffer sb = new StringBuffer();
for(int i = 0;i < sortList.size();i++){
String key = sortList.get(i);
sb.append(key).append("=").append(map.get(key)).append("&");
}
sb.append(bindKey).append("=").append(secretKey);
//最终获取到的需要加密的字符串
System.out.println("排序后的字符串:" + sb.toString());
return Test.encryptToMD5(sb.toString());
}
}
下面图片展示我们服务端具体的代码实现