开放平台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
}