开放平台Token加密方式
版本:v0.0.1
最新更新日期:2022-03-17
更新日志
日期 | 变更类别 | 说明 |
2022-03-17 | 更新 | token生成方式 |
一、背景介绍
根据商家需求需要与蓉卡系统对接。
信息输出方:商户
信息接收方:成都蓉卡科技有限公司
二、技术方案
由成都蓉卡科技有限公司出具接口文档的约定(本文档下文)。
三、接入步骤
商家向蓉卡销售人员获取(mid、rsa私钥);
根据蓉卡科技有限公司提供的接口上传数据;
四、接口协议
4.1 接口签名方案
商家请求接口时,会带上签名参数。因此厂商接口需要校验签名是否合法,避免被第三方恶意调用,导致信息泄漏。
请求接口的HTTP header中加上这些http请求头(全部小写)
'mid': 'xxxx', 'token': 'xxxxx'
其中mid为颁发的mid,token为商家rsa私钥加密的随机字符串。
签名的构建方式是:sign=a×tamp=1648287087,timestamp为当前十位时间戳(秒),sign为传输数据按字母排序后MD5小写的数据;
另外,timestamp有5分钟过期的判断。
签名的mid和rsa私钥由蓉卡销售人员提供。
HTTP的Content-Type请使用application/json
接口里的鉴权php代码示例:
SIGN签名生成: /** * @param $data * 获取需要的签名 */ protected function getSign($data) { ksort($data); $str = ""; foreach ($data as $k => $value) $str .= '&' . $k . '=' . $value; $str = substr($str, 1); return md5($str); } TOKEN生成: $token = ['timestamp' => time(),'sign' => $this->getSign()]; $token = http_build_query($token); $rsa = RSA::rsaPrivateEncrypt($key->private_secret, $token); /** * @param $private :私钥字符串 * @param $str :待加密的字符串 * @return false:加密失败,true成功返回base64数据 * 私钥加密PHP版本 */ public function rsaPrivateEncrypt($private, $str) { $private = openssl_pkey_get_private($private); if (!$private) { return false; } $crypto = ''; foreach (str_split($str, 117) as $chunk) { openssl_private_encrypt($chunk, $encryptData, $private); $crypto .= $encryptData; } if (!$crypto) { return false; } return base64_encode($crypto); }
接口里的鉴权java代码示例:
/** * 加密算法RSA */ private val KEY_ALGORITHM = "RSA" /** * 加密算法RSA */ private val KEY_TRANSFORMATION = "RSA/ECB/PKCS1Padding" /** * RSA最大加密明文大小 */ private val MAX_ENCRYPT_BLOCK = 117 /** * RSA最大解密密文大小 */ private val MAX_DECRYPT_BLOCK = 128 /** * 私钥加密 * @param data 源数据 * @param privateKey 私钥(BASE64编码) * @return * @throws Exception */ fun encryptByPrivateKey(data: ByteArray, privateKey: String?): ByteArray? { val keyBytes: ByteArray = base64Decode(privateKey) val pkcs8KeySpec = PKCS8EncodedKeySpec(keyBytes) val keyFactory = KeyFactory.getInstance(KEY_ALGORITHM) val privateK: Key = keyFactory.generatePrivate(pkcs8KeySpec) val cipher = Cipher.getInstance(KEY_TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, privateK) val inputLen = data.size val out = ByteArrayOutputStream() var offSet = 0 var cache: ByteArray var i = 0 // 对数据分段加密 while (inputLen - offSet > 0) { cache = if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK) } else { cipher.doFinal(data, offSet, inputLen - offSet) } out.write(cache, 0, cache.size) i++ offSet = i * MAX_ENCRYPT_BLOCK } val encryptedData = out.toByteArray() out.close() return encryptedData }