- 11 个已跟踪文件的在途改动此前只存在于工作区,生产已在运行 - 补入两个从未入库的文件:InternalController.php(app_03/box_app 内部接口)、 config/internal.php(内部通信 key,值从 .env 读取,不含硬编码密钥) - 逐文件 md5 比对过生产,内容一致 Co-authored-by: Cursor <cursoragent@cursor.com>
135 lines
5.1 KiB
PHP
135 lines
5.1 KiB
PHP
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||
// +----------------------------------------------------------------------
|
||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||
// +----------------------------------------------------------------------
|
||
// | Author: CRMEB Team <admin@crmeb.com>
|
||
// +----------------------------------------------------------------------
|
||
|
||
namespace app\controller\api\v1;
|
||
|
||
use app\Request;
|
||
use app\services\user\UserServices;
|
||
use app\services\wechat\RoutineServices;
|
||
use app\services\wechat\WechatUserServices;
|
||
use think\db\exception\DataNotFoundException;
|
||
use think\db\exception\DbException;
|
||
use think\db\exception\ModelNotFoundException;
|
||
use think\exception\ValidateException;
|
||
use think\Response;
|
||
|
||
/**
|
||
* 内部服务接口(不经过用户认证)
|
||
* 用于 H5 / app_03 后端通过 openid 自动补齐用户信息
|
||
*/
|
||
class InternalController
|
||
{
|
||
/**
|
||
* 验证内部 API Key
|
||
* @param Request $request
|
||
* @return bool true=通过,false=拒绝
|
||
*/
|
||
private function checkInternalKey(Request $request): bool
|
||
{
|
||
$apiKey = $request->header('X-Internal-Key');
|
||
// 注意:在 Swoole 沙箱里 env()/getenv() 经常读不到 .env
|
||
// 用 config() 兜底,确保两种部署(PHP-FPM / Swoole)都生效
|
||
$configKey = (string)(config('internal.api_key') ?: env('INTERNAL_API_KEY', ''));
|
||
return $apiKey && $configKey && $apiKey === $configKey;
|
||
}
|
||
|
||
/**
|
||
* 根据 openid 获取用户信息
|
||
* @param Request $request
|
||
* @param WechatUserServices $wechatUserServices
|
||
* @return Response
|
||
*/
|
||
public function userInfo(Request $request, WechatUserServices $wechatUserServices): Response
|
||
{
|
||
if (!$this->checkInternalKey($request)) {
|
||
return Response::create(['code' => 403, 'msg' => 'Forbidden'], 'json');
|
||
}
|
||
|
||
$openid = $request->param('openid', '');
|
||
if (!$openid) {
|
||
return Response::create(['code' => 400, 'msg' => 'openid is required'], 'json');
|
||
}
|
||
|
||
try {
|
||
$wechatUser = $wechatUserServices->getWechatUserInfo(['openid' => $openid]);
|
||
} catch (DataNotFoundException | ModelNotFoundException | DbException $e) {
|
||
return Response::create(['code' => 500, 'msg' => '查询失败'], 'json');
|
||
}
|
||
if (!$wechatUser) {
|
||
return Response::create(['code' => 404, 'msg' => 'user not found'], 'json');
|
||
}
|
||
|
||
$uid = (int)$wechatUser['uid'];
|
||
$userServices = app()->make(UserServices::class);
|
||
try {
|
||
$user = $userServices->getUserInfo($uid);
|
||
} catch (DataNotFoundException | ModelNotFoundException | DbException $e) {
|
||
$user = null;
|
||
}
|
||
|
||
return Response::create([
|
||
'code' => 200,
|
||
'data' => [
|
||
'uid' => $uid,
|
||
'nickname' => $user['nickname'] ?? $wechatUser['nickname'] ?? '',
|
||
'phone' => $user['phone'] ?? $wechatUser['phone'] ?? '',
|
||
'avatar' => $user['avatar'] ?? $wechatUser['headimgurl'] ?? '',
|
||
],
|
||
], 'json');
|
||
}
|
||
|
||
/**
|
||
* 通过微信 code 换 openid(绕过 store_user_mobile 限制)
|
||
*
|
||
* 设计目的:H5/app_03 在新用户场景下(CRMEB 强制绑手机号=true),
|
||
* 原 silenceAuth 返回 {auth_login:1, key:...},前端拿不到 openid 会被
|
||
* 引导到授权页。本端点只调微信 code2session 拿 openid/unionid,不查
|
||
* store_user_mobile、不建用户、不发 token,前端拿到 openid 后走自己的
|
||
* openid-login 即可自助登录。
|
||
*
|
||
* @param Request $request
|
||
* @param RoutineServices $routineServices
|
||
* @return Response
|
||
*/
|
||
public function getOpenidByCode(Request $request, RoutineServices $routineServices): Response
|
||
{
|
||
if (!$this->checkInternalKey($request)) {
|
||
return Response::create(['code' => 403, 'msg' => 'Forbidden'], 'json');
|
||
}
|
||
|
||
$code = $request->param('code', '');
|
||
if (!$code) {
|
||
return Response::create(['code' => 400, 'msg' => 'code is required'], 'json');
|
||
}
|
||
|
||
try {
|
||
$wechatInfo = $routineServices->getUserInfoByCode((string)$code);
|
||
} catch (ValidateException $e) {
|
||
return Response::create(['code' => 400, 'msg' => $e->getMessage()], 'json');
|
||
} catch (\Throwable $e) {
|
||
return Response::create(['code' => 500, 'msg' => 'code2session 失败: ' . $e->getMessage()], 'json');
|
||
}
|
||
|
||
$openid = $wechatInfo['openid'] ?? '';
|
||
if (!$openid) {
|
||
return Response::create(['code' => 500, 'msg' => 'openid 缺失'], 'json');
|
||
}
|
||
|
||
return Response::create([
|
||
'code' => 200,
|
||
'data' => [
|
||
'openid' => $openid,
|
||
'unionid' => $wechatInfo['unionid'] ?? '',
|
||
],
|
||
], 'json');
|
||
}
|
||
}
|