项目级Java接口签名与验证实现

您所在的位置:网站首页 签名录入 项目级Java接口签名与验证实现

项目级Java接口签名与验证实现

2024-03-18 15:57| 来源: 网络整理| 查看: 265

在一些项目中,客户端在调用服务的接口时,通常需要设置签名验证,以保证对客户端的认证。在签名过程中一般每个公司都有自己的签名规则和签名算法,广泛使用的是使用非对称加密算法RSA为核心,在客户端使用私钥对参数进行加密生成一个密钥,传给服务端,然后在服务端再对这个这个密钥使用公钥进行解密,解密出来的字符串参数与客户端传过来的参数进行对比,如果一样,验证成功。

总结起来就是:

客户端

首先获取所有的参数,然后对他们进行排序,生成一个字符串

对这个字符串MD5加密,然后转为大写

然后使用私钥对MD5再次加密,生成最终的签名sign

把这个签名sign传给服务端

服务端

获取所有的参数

把参数中签名sign参数去除,然后排序,生成一个字符串

对这个字符串MD5加密,然后转为大写

使用公钥对sign字符串进行解密获取一个String,然后和第三步中获取的字符串相对,如果相等,则验证成功

下面我们就通过以上规则实现客户端的签名和服务端的验证。

客户端签名

比如我们这是我们的url:

http://localhost:8080/task/test?name=张三&age=8×tamp=1591261543133

可以看到url中有三个参数,分别是姓名、年龄和时间戳。首先我们要对这些参数进行排序:

public static String getSortedContent(Map data) { StringBuffer content = new StringBuffer(); List keys = new ArrayList(data.keySet()); Collections.sort(keys); int index = 0; for (String key : keys) { String value = data.get(key); content.append((index == 0 ? "" : "&")).append(key).append("=").append(value); index++; } return content.toString(); }

然后对排序好的字符串进行加密,然后转大写:

String summary = DigestUtils.md5Hex(data).toLowerCase();

最后对summary进行私钥加密:

public static String EncryptByRSAPriKey(String content,String priKey) throws Exception { try { PrivateKey privateKey = SecurityUtil.getRSAPriKey(priKey); Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); cipher.update(content.getBytes(SecurityUtil.RSA_CHARSET)); return SecurityUtil.encodeBase64(cipher.doFinal()); } catch (Exception e) { e.printStackTrace(); throw new Exception(); } }

最终得到我们想要的sign,传给服务端。

服务端验证

首先获取到所有的参数后,去除sign,对剩下的参数排序,MD5加密,转大写,

/** * * @param params 去除sign的所有参数 * @param sign * @param pubKey 公钥 * @return * @throws ApiError */ public static boolean verifySign( Map params,String sign,String pubKey) throws ApiError { if (StringUtil.isEmpty(sign)) { return false; } String signType = params.get(Constants.FN_SIGN_TYPE);; ​ //暂不支持非RSA的签名 if (StringUtil.isEmpty(signType) || !signType.equals(Constants.SIGN_TYPE_RSA)) { return false; } //参与签名的数据 String data = ApiUtils.getSortedContent(params); ApiLogger.getLogger().debug("sign data:" + data); String summary = DigestUtils.md5Hex(data).toLowerCase(); ApiLogger.getLogger().debug("sign summary:" + summary); ​ String summaryDecode = null; try { summaryDecode = SecurityUtil.DecryptByRSAPubKey(sign, pubKey); } catch (Exception e) { throw new ApiError("do_digest_error", e); } return summary.equals(summaryDecode); }

其中SecurityUtil.DecryptByRSAPubKey(sign, pubKey)的方法为:

/** * * 描述:将字符串通过RSA算法公钥解密 * @author wangbing * @since * @param content 需要解密的内容 * @param pubKey 公钥 * @return 解密后字符串 * @throws Exception */ public static String DecryptByRSAPubKey(String content, String pubKey){ try { PublicKey publicKey = SecurityUtil.getRSAPubKey(priKey); Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); cipher.update(SecurityUtil.decodeBase64(content)); return new String(cipher.doFinal(), SecurityUtil.RSA_CHARSET); } catch (Exception e) { e.printStackTrace(); } return null; }

到此,服务端的核心代码完成。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3