2025-10-20 09:23:30 +08:00

302 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace addons\shopro\controller;
use addons\shopro\controller\Common;
use addons\shopro\library\ccblife\CcbUrlDecrypt;
use app\admin\model\shopro\user\User;
use think\Db;
use think\Log;
/**
* 建行生活用户登录控制器
* 处理建行用户登录、绑定、参数解密等功能
*/
class Ccblife extends Common
{
/**
* 不需要登录的方法
* @var array
*/
protected $noNeedLogin = ['autoLogin', 'login', 'callback', 'decryptParam'];
/**
* 不需要权限的方法
* @var array
*/
protected $noNeedRight = ['*'];
/**
* 建行生活用户登录URL跳转方式
* 建行App会携带加密参数跳转到此地址
*
* GET /addons/shopro/ccblife/login
*/
public function login()
{
try {
// 获取URL参数
$ccbParamSJ = $this->request->get('ccbParamSJ', '');
$otherParams = $this->request->get();
// 验证必要参数
if (empty($ccbParamSJ)) {
$this->error('缺少必要参数');
}
// 获取配置
$config = config('ccblife');
// 解密参数(使用服务方私钥)
$decryptedParams = CcbUrlDecrypt::decrypt($ccbParamSJ, $config['private_key']);
if (!$decryptedParams) {
$this->error('参数解密失败');
}
// 合并所有参数
$allParams = array_merge($otherParams, $decryptedParams);
// 获取建行用户信息
$ccbUserId = $allParams['userid'] ?? '';
$mobile = $allParams['mobile'] ?? '';
$openId = $allParams['openid'] ?? '';
if (empty($ccbUserId)) {
$this->error('用户信息获取失败');
}
// 处理用户登录/注册
$userInfo = $this->processUserLogin($ccbUserId, $mobile, $openId, $allParams);
// 生成商城Token
$this->auth->direct($userInfo['user_id']);
$token = $this->auth->getToken();
// 构建跳转URL
$redirectUrl = $allParams['redirect_url'] ?? '/pages/index/index';
$this->success('登录成功', [
'token' => $token,
'user_info' => $userInfo,
'redirect_url' => $redirectUrl
]);
} catch (\Exception $e) {
Log::error('建行生活登录失败: ' . $e->getMessage());
$this->error($e->getMessage());
}
}
/**
* 建行用户自动登录JSBridge方式
* H5在建行App内打开时,通过JSBridge获取用户信息后调用
*
* POST /addons/shopro/ccblife/autoLogin
*/
public function autoLogin()
{
try {
// 获取请求参数
$ccbUserId = $this->request->post('ccb_user_id', '');
$mobile = $this->request->post('mobile', '');
$nickname = $this->request->post('nickname', '');
$avatar = $this->request->post('avatar', '');
// 验证必需参数
if (empty($ccbUserId)) {
$this->error('建行用户ID不能为空');
}
// 处理用户登录/注册
$userInfo = $this->processUserLogin($ccbUserId, $mobile, '', [
'nickname' => $nickname,
'avatar' => $avatar
]);
// 使用Auth系统登录并生成Token
$this->auth->direct($userInfo['user_id']);
$token = $this->auth->getToken();
// 返回结果
$this->success('登录成功', [
'token' => $token,
'user_id' => $userInfo['user_id'],
'is_new_user' => $userInfo['is_new'],
'userInfo' => $userInfo
]);
} catch (\Exception $e) {
Log::error('建行自动登录失败: ' . $e->getMessage());
$this->error('登录失败: ' . $e->getMessage());
}
}
/**
* 处理用户登录/注册
*
* @param string $ccbUserId 建行用户ID
* @param string $mobile 手机号
* @param string $openId OpenID
* @param array $params 其他参数
* @return array 用户信息
*/
private function processUserLogin($ccbUserId, $mobile, $openId, $params)
{
Db::startTrans();
try {
// 查询是否已存在建行用户
$user = Db::name('user')->where('ccb_user_id', $ccbUserId)->find();
if ($user) {
// 用户已存在,更新登录信息
$isNew = false;
Db::name('user')->where('id', $user['id'])->update([
'logintime' => time(),
'loginip' => $this->request->ip(),
'updatetime' => time()
]);
} else {
// 用户不存在,先尝试通过手机号查找
if ($mobile) {
$user = Db::name('user')->where('mobile', $mobile)->find();
}
if ($user) {
// 手机号已存在更新建行用户ID
$isNew = false;
Db::name('user')->where('id', $user['id'])->update([
'ccb_user_id' => $ccbUserId,
'logintime' => time(),
'loginip' => $this->request->ip(),
'updatetime' => time()
]);
} else {
// 创建新用户
$isNew = true;
$userData = [
'ccb_user_id' => $ccbUserId,
'username' => 'ccb_' . substr(md5($ccbUserId), 0, 8),
'nickname' => $params['nickname'] ?? '建行用户' . substr($ccbUserId, -4),
'mobile' => $mobile,
'avatar' => $params['avatar'] ?? '/assets/img/avatar.png',
'status' => 'normal',
'salt' => \fast\Random::alnum(),
'password' => '', // 建行用户无需密码
'joinip' => $this->request->ip(),
'jointime' => time(),
'logintime' => time(),
'loginip' => $this->request->ip(),
'createtime' => time(),
'updatetime' => time()
];
// 设置随机密码
$userData['password'] = md5(md5(\fast\Random::alnum(32)) . $userData['salt']);
$userId = Db::name('user')->insertGetId($userData);
$user = Db::name('user')->where('id', $userId)->find();
}
}
Db::commit();
return [
'user_id' => $user['id'],
'nickname' => $user['nickname'],
'avatar' => $user['avatar'],
'mobile' => $this->maskMobile($user['mobile']),
'is_new' => $isNew,
'ccb_user_id' => $ccbUserId
];
} catch (\Exception $e) {
Db::rollback();
throw $e;
}
}
/**
* 解密建行参数(调试用)
* 用于前端测试页面解密建行传递的加密参数
*
* POST /addons/shopro/ccblife/decryptParam
*/
public function decryptParam()
{
try {
// 获取加密参数
$ccbParamSJ = $this->request->post('ccbParamSJ', '');
if (empty($ccbParamSJ)) {
$this->error('缺少 ccbParamSJ 参数');
}
// 从插件配置文件直接加载避免config()缓存问题)
$configFile = __DIR__ . '/../config/ccblife.php';
if (!file_exists($configFile)) {
$this->error('建行配置文件不存在');
}
$config = include $configFile;
// 验证配置
if (empty($config['private_key'])) {
$this->error('配置错误private_key 为空');
}
Log::info('解密建行参数', [
'ccbParamSJ_length' => strlen($ccbParamSJ),
'service_id' => $config['service_id'],
'private_key_length' => strlen($config['private_key'])
]);
// 解密参数(使用服务方私钥)
$decryptedParams = CcbUrlDecrypt::decrypt($ccbParamSJ, $config['private_key']);
if ($decryptedParams === false || empty($decryptedParams)) {
// 检查日志文件获取详细错误
$logFile = RUNTIME_PATH . 'log/' . date('Ymd') . '.log';
$errorDetail = '';
if (file_exists($logFile)) {
$logContent = file_get_contents($logFile);
// 提取最后几行日志
$lines = explode("\n", $logContent);
$errorDetail = implode("\n", array_slice($lines, -10));
}
$this->error('参数解密失败,请查看日志: ' . $errorDetail);
}
// 返回解密后的数据
$this->success('解密成功', $decryptedParams);
} catch (\Exception $e) {
Log::error('建行参数解密失败', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
$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);
}
}