mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-17 21:03:17 +08:00
修改解码代码
This commit is contained in:
parent
3f452ca979
commit
7df1bbdf19
@ -137,7 +137,7 @@ class Ccblife extends Common
|
||||
* @param string $ccbUserId 建行用户ID
|
||||
* @param string $mobile 手机号
|
||||
* @param string $openId OpenID
|
||||
* @param array $params 其他参数
|
||||
* @param array $params 其他参数(包含 Usr_Name 等建行返回的数据)
|
||||
* @return array 用户信息
|
||||
*/
|
||||
private function processUserLogin($ccbUserId, $mobile, $openId, $params)
|
||||
@ -152,41 +152,67 @@ class Ccblife extends Common
|
||||
$isNew = false;
|
||||
|
||||
Db::name('user')->where('id', $user['id'])->update([
|
||||
'prevtime' => $user['logintime'] ?? null, // 记录上次登录时间
|
||||
'logintime' => time(),
|
||||
'loginip' => $this->request->ip(),
|
||||
'updatetime' => time()
|
||||
]);
|
||||
|
||||
// 重新获取更新后的用户信息
|
||||
$user = Db::name('user')->where('id', $user['id'])->find();
|
||||
|
||||
} else {
|
||||
// 用户不存在,先尝试通过手机号查找
|
||||
if ($mobile) {
|
||||
if (!empty($mobile)) {
|
||||
$user = Db::name('user')->where('mobile', $mobile)->find();
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
// 手机号已存在,更新建行用户ID
|
||||
// 手机号已存在,绑定建行用户ID
|
||||
$isNew = false;
|
||||
|
||||
Db::name('user')->where('id', $user['id'])->update([
|
||||
'ccb_user_id' => $ccbUserId,
|
||||
'prevtime' => $user['logintime'] ?? null,
|
||||
'logintime' => time(),
|
||||
'loginip' => $this->request->ip(),
|
||||
'updatetime' => time()
|
||||
]);
|
||||
|
||||
// 重新获取更新后的用户信息
|
||||
$user = Db::name('user')->where('id', $user['id'])->find();
|
||||
|
||||
} else {
|
||||
// 创建新用户
|
||||
$isNew = true;
|
||||
|
||||
// 从建行参数中获取用户名(Usr_Name 或 nickname)
|
||||
$userName = $params['Usr_Name'] ?? $params['nickname'] ?? '';
|
||||
if (empty($userName)) {
|
||||
$userName = '建行用户' . substr($ccbUserId, -4);
|
||||
}
|
||||
|
||||
// 生成盐值
|
||||
$salt = \fast\Random::alnum();
|
||||
|
||||
$userData = [
|
||||
'ccb_user_id' => $ccbUserId,
|
||||
'username' => 'ccb_' . substr(md5($ccbUserId), 0, 8),
|
||||
'nickname' => $params['nickname'] ?? '建行用户' . substr($ccbUserId, -4),
|
||||
'mobile' => $mobile,
|
||||
'username' => 'ccb_' . substr(md5($ccbUserId), 0, 10), // 唯一用户名
|
||||
'nickname' => $userName,
|
||||
'mobile' => $mobile ?: '',
|
||||
'avatar' => $params['avatar'] ?? '/assets/img/avatar.png',
|
||||
'status' => 'normal',
|
||||
'salt' => \fast\Random::alnum(),
|
||||
'password' => '', // 建行用户无需密码
|
||||
'salt' => $salt,
|
||||
'password' => md5(md5(\fast\Random::alnum(32)) . $salt), // 随机密码
|
||||
'group_id' => 0, // 默认用户组
|
||||
'level' => 0, // 默认等级
|
||||
'gender' => 0, // 未知性别
|
||||
'money' => 0.00,
|
||||
'commission' => 0.00,
|
||||
'score' => 0,
|
||||
'successions' => 1,
|
||||
'maxsuccessions' => 1,
|
||||
'loginfailure' => 0,
|
||||
'joinip' => $this->request->ip(),
|
||||
'jointime' => time(),
|
||||
'logintime' => time(),
|
||||
@ -195,27 +221,45 @@ class Ccblife extends Common
|
||||
'updatetime' => time()
|
||||
];
|
||||
|
||||
// 设置随机密码
|
||||
$userData['password'] = md5(md5(\fast\Random::alnum(32)) . $userData['salt']);
|
||||
Log::info('创建建行新用户', [
|
||||
'ccb_user_id' => $ccbUserId,
|
||||
'mobile' => $mobile,
|
||||
'nickname' => $userName
|
||||
]);
|
||||
|
||||
$userId = Db::name('user')->insertGetId($userData);
|
||||
if (!$userId) {
|
||||
throw new \Exception('创建用户失败');
|
||||
}
|
||||
|
||||
$user = Db::name('user')->where('id', $userId)->find();
|
||||
}
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
|
||||
Log::info('建行用户登录处理成功', [
|
||||
'user_id' => $user['id'],
|
||||
'ccb_user_id' => $ccbUserId,
|
||||
'is_new' => $isNew
|
||||
]);
|
||||
|
||||
return [
|
||||
'user_id' => $user['id'],
|
||||
'nickname' => $user['nickname'],
|
||||
'avatar' => $user['avatar'],
|
||||
'mobile' => $this->maskMobile($user['mobile']),
|
||||
'mobile' => $user['mobile'],
|
||||
'is_new' => $isNew,
|
||||
'ccb_user_id' => $ccbUserId
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
Log::error('建行用户登录处理失败', [
|
||||
'error' => $e->getMessage(),
|
||||
'ccb_user_id' => $ccbUserId,
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
@ -283,19 +327,4 @@ class Ccblife extends Common
|
||||
$this->error('解密失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号脱敏
|
||||
*
|
||||
* @param string $mobile 手机号
|
||||
* @return string 脱敏后的手机号
|
||||
*/
|
||||
private function maskMobile($mobile)
|
||||
{
|
||||
if (empty($mobile) || strlen($mobile) !== 11) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return substr($mobile, 0, 3) . '****' . substr($mobile, -4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,14 @@ class CcbUrlDecrypt
|
||||
{
|
||||
/**
|
||||
* 解密建行URL参数ccbParamSJ
|
||||
* 流程:URLDecode -> RSA解密(使用服务方私钥,内部会进行BASE64解码)
|
||||
*
|
||||
* 建行加密流程(参考Java demo):
|
||||
* 1. 原文 → RSA公钥加密 → BASE64编码(第一次)
|
||||
* 2. 再把结果转UTF-8字节 → BASE64编码(第二次)
|
||||
*
|
||||
* 解密流程:
|
||||
* 1. URLDecode → BASE64解码(第一次)→ BASE64解码(第二次)
|
||||
* 2. RSA私钥解密 → 原文
|
||||
*
|
||||
* @param string $ccbParamSJ 加密的参数字符串(可能已经URLDecode)
|
||||
* @param string $privateKey 服务方私钥(BASE64格式或PEM格式)
|
||||
@ -22,7 +29,7 @@ class CcbUrlDecrypt
|
||||
{
|
||||
try {
|
||||
// 调试日志
|
||||
trace('开始解密建行参数(RSA方式)', 'info');
|
||||
trace('开始解密建行参数(双重BASE64 + RSA)', 'info');
|
||||
trace('ccbParamSJ 长度: ' . strlen($ccbParamSJ), 'info');
|
||||
|
||||
// 验证输入
|
||||
@ -34,12 +41,26 @@ class CcbUrlDecrypt
|
||||
throw new \Exception('privateKey 为空');
|
||||
}
|
||||
|
||||
// URLDecode(如果还没有解码)
|
||||
// 步骤1: URLDecode(如果还没有解码)
|
||||
$urlDecoded = urldecode($ccbParamSJ);
|
||||
trace('URLDecode后长度: ' . strlen($urlDecoded), 'info');
|
||||
|
||||
// RSA解密(CcbRSA::decrypt内部会自动进行BASE64解码)
|
||||
$decrypted = CcbRSA::decrypt($urlDecoded, $privateKey);
|
||||
// 步骤2: 第一次 BASE64 解码
|
||||
$firstDecode = base64_decode($urlDecoded);
|
||||
if ($firstDecode === false || empty($firstDecode)) {
|
||||
throw new \Exception('第一次 BASE64 解码失败');
|
||||
}
|
||||
trace('第一次BASE64解码成功,长度: ' . strlen($firstDecode), 'info');
|
||||
|
||||
// 步骤3: 第二次 BASE64 解码(建行特殊之处:双重BASE64编码)
|
||||
$secondDecode = base64_decode($firstDecode);
|
||||
if ($secondDecode === false || empty($secondDecode)) {
|
||||
throw new \Exception('第二次 BASE64 解码失败');
|
||||
}
|
||||
trace('第二次BASE64解码成功,长度: ' . strlen($secondDecode), 'info');
|
||||
|
||||
// 步骤4: RSA 私钥解密(直接处理二进制数据,不再用 CcbRSA::decrypt)
|
||||
$decrypted = self::rsaPrivateDecrypt($secondDecode, $privateKey);
|
||||
if ($decrypted === false || empty($decrypted)) {
|
||||
throw new \Exception('RSA解密失败');
|
||||
}
|
||||
@ -47,7 +68,7 @@ class CcbUrlDecrypt
|
||||
trace('RSA解密成功,长度: ' . strlen($decrypted), 'info');
|
||||
trace('解密内容: ' . $decrypted, 'info');
|
||||
|
||||
// 解析参数字符串为数组
|
||||
// 步骤5: 解析参数字符串为数组
|
||||
parse_str($decrypted, $params);
|
||||
|
||||
if (empty($params)) {
|
||||
@ -66,6 +87,58 @@ class CcbUrlDecrypt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA 私钥分块解密(不做 BASE64 解码)
|
||||
*
|
||||
* @param string $encryptedData 加密的二进制数据
|
||||
* @param string $privateKey 私钥(BASE64或PEM格式)
|
||||
* @return string|false 解密后的数据
|
||||
*/
|
||||
private static function rsaPrivateDecrypt($encryptedData, $privateKey)
|
||||
{
|
||||
try {
|
||||
// 格式化私钥为 PEM 格式
|
||||
$pemPrivateKey = $privateKey;
|
||||
if (strpos($pemPrivateKey, '-----BEGIN') === false) {
|
||||
$pemPrivateKey = preg_replace('/\s+/', '', $pemPrivateKey);
|
||||
$pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
|
||||
chunk_split($pemPrivateKey, 64, "\n") .
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
|
||||
// 加载私钥资源
|
||||
$priKey = openssl_pkey_get_private($pemPrivateKey);
|
||||
if (!$priKey) {
|
||||
throw new \Exception('私钥格式错误: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
// 获取密钥大小
|
||||
$keyDetails = openssl_pkey_get_details($priKey);
|
||||
$keySize = $keyDetails['bits'] / 8; // 1024位 = 128字节
|
||||
|
||||
// 分块解密
|
||||
$blocks = str_split($encryptedData, $keySize);
|
||||
$decrypted = '';
|
||||
|
||||
foreach ($blocks as $block) {
|
||||
$decryptedBlock = '';
|
||||
$success = openssl_private_decrypt($block, $decryptedBlock, $priKey, OPENSSL_PKCS1_PADDING);
|
||||
if (!$success) {
|
||||
throw new \Exception('RSA分块解密失败: ' . openssl_error_string());
|
||||
}
|
||||
$decrypted .= $decryptedBlock;
|
||||
}
|
||||
|
||||
openssl_free_key($priKey);
|
||||
|
||||
return $decrypted;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
trace('RSA私钥解密错误: ' . $e->getMessage(), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DES解密
|
||||
* 使用ECB模式,PKCS5Padding填充
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user