- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
<?php
namespace addons\shopro\service\third\apple;
use app\common\library\Auth;
use addons\shopro\service\user\UserAuth;
use app\admin\model\shopro\ThirdOauth;
class Apple
{
public function __construct()
{
}
/**
* AppleId登陆
*
* @return array
*/
public function login($payload)
{
$identityToken = $payload['identityToken'];
$openId = $payload['openId'];
$appleSignInPayload = \AppleSignIn\ASDecoder::getAppleSignInPayload($identityToken);
$isValid = $appleSignInPayload->verifyUser($openId);
if (!$isValid) return false;
$nickname = '';
if (!empty($payload['fullName'])) {
$hasFamilyName = !empty($payload['fullName']['familyName']);
$nickname = ($hasFamilyName ? $payload['fullName']['familyName'] : '') . ($hasFamilyName ? ' ' : '') . $payload['fullName']['giveName'];
}
$appleUser = [
'openid' => $openId,
'nickname' => $nickname,
'avatar' => ''
];
$oauthInfo = $this->createOrUpdateOauthInfo($appleUser);
if (!$oauthInfo->user_id) {
$this->registerOrBindUser($oauthInfo);
}
$auth = Auth::instance();
$ret = $auth->direct($oauthInfo->user_id);
if ($ret) {
$oauthInfo->login_num += 1;
set_token_in_header($auth->getToken());
return true;
} else {
$oauthInfo->user_id = 0;
$oauthInfo->save();
return false;
}
}
/**
* 创建/更新用户认证信息
*
* @return think\Model
*/
private function createOrUpdateOauthInfo($appleUser)
{
$oauthInfo = ThirdOauth::where([
'openid' => $appleUser['openid'],
'provider' => 'apple',
'platform' => 'App'
])->find();
if (!$oauthInfo) { // 创建新的third_oauth条目
$appleUser['provider'] = 'apple';
$appleUser['platform'] = 'App';
ThirdOauth::create($appleUser);
$oauthInfo = ThirdOauth::where([
'openid' => $appleUser['openid'],
'provider' => 'apple',
'platform' => 'App'
])->find();
}
if ($oauthInfo) { // 更新授权信息
$oauthInfo->save($appleUser);
}
return $oauthInfo;
}
/**
* 注册/绑定用户
*
* @return think\Model
*/
private function registerOrBindUser($oauthInfo, $user_id = 0)
{
if ($oauthInfo->user_id) {
error_stop('该账号已绑定其他用户');
}
if ($user_id === 0) { // 注册新用户
$user = (new UserAuth())->register([
'nickname' => $oauthInfo->nickname,
'avatar' => $oauthInfo->avatar,
]);
$user_id = $user->id;
}
$oauthInfo->user_id = $user_id;
return $oauthInfo->save();
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace addons\shopro\service\third\wechat;
use addons\shopro\facade\Wechat;
use fast\Random;
use app\common\library\Auth;
use app\admin\model\shopro\ThirdOauth;
class MiniProgram
{
public $wechat;
protected $request;
protected $payload;
public function __construct($payload = [])
{
$this->payload = $payload;
$this->wechat = Wechat::miniProgram();
}
// 小程序登录
public function login()
{
// https://developers.weixin.qq.com/community/develop/doc/00022c683e8a80b29bed2142b56c01
if (empty($this->payload['sessionId'])) {
error_stop('未获取到登陆态, 请重试', -1);
}
$sessionData = redis_cache($this->payload['sessionId']);
if (empty($sessionData)) {
error_stop('登陆态已过期, 请重试', -1);
}
$wechatUser = [
'openid' => $sessionData['openid'],
'unionid' => $sessionData['unionid'] ?? '',
'mobile' => '',
'avatar' => '',
'nickname' => '',
];
return $wechatUser;
}
public function bind()
{
if (empty($this->payload['sessionId'])) {
error_stop('未获取到登陆态, 请重试', -1);
}
$sessionData = redis_cache($this->payload['sessionId']);
if (empty($sessionData)) {
error_stop('登陆态已过期, 请重试', -1);
}
$wechatUser = [
'openid' => $sessionData['openid'],
'unionid' => $sessionData['unionid'] ?? '',
'avatar' => '',
'nickname' => '',
];
return $wechatUser;
}
// 解密微信小程序手机号
public function getUserPhoneNumber()
{
if (empty($this->payload['sessionId'])) {
error_stop('未获取到登陆态, 请重试', -1);
}
$sessionData = redis_cache($this->payload['sessionId']);
if (empty($sessionData)) {
error_stop('登陆态已过期, 请重试', -1);
}
$phoneInfo = $this->wechat->encryptor->decryptData($sessionData['session_key'], $this->payload['iv'], $this->payload['encryptedData']);
if (empty($phoneInfo['purePhoneNumber'])) {
error_stop('获取失败,请重试');
}
if ($phoneInfo['countryCode'] !== '86') {
error_stop('仅支持大陆地区手机号');
}
return $phoneInfo['purePhoneNumber'];
}
/**
* 获取session_id, 缓存 session_key, openid (unionid), 自动登录
*
* @return string
*/
public function getSessionId()
{
if (empty($this->payload['code'])) {
error_stop('缺少code参数');
}
$decryptData = $this->wechat->auth->session($this->payload['code']);
if(!empty($decryptData['errmsg'])) {
error_stop($decryptData['errmsg']);
}
if (empty($decryptData['session_key'])) {
error_stop('未获取到登陆态, 请重试', -1);
}
$auto_login = $this->payload['auto_login'] ?? false;
// 自动登录流程
if($auto_login) {
$oauthInfo = ThirdOauth::getByOpenid($decryptData['openid']);
if($oauthInfo && $oauthInfo->user_id) {
$auth = Auth::instance();
$ret = $auth->direct($oauthInfo->user_id);
if ($ret) {
set_token_in_header($auth->getToken());
}
}
}
$session_id = Random::uuid();
redis_cache($session_id, $decryptData, 60 * 60 * 24 * 7); // session_key缓存保留一周
return ['session_id' => $session_id, 'auto_login' => $auto_login];
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace addons\shopro\service\third\wechat;
use addons\shopro\facade\Wechat;
class OfficialAccount
{
public $wechat;
protected $request;
protected $payload;
public function __construct($payload)
{
$this->payload = $payload;
$this->request = request();
$this->wechat = Wechat::officialAccount();
}
public function login()
{
$code = $this->request->get('code');
if (empty($code)) {
error_stop('缺少code参数');
}
$decryptData = $this->wechat->oauth->user()->getOriginal();
$wechatUser = [
'openid' => $decryptData['openid'],
'unionid' => $decryptData['unionid'] ?? '',
'avatar' => $decryptData['headimgurl'],
'nickname' => $decryptData['nickname'],
];
return $wechatUser;
}
public function bind()
{
return $this->login();
}
/**
* 获取网页登录地址redirect+返回code
*
* @return string
*/
public function oauthLogin()
{
// 返回前端
if (!empty($this->request->param('code'))) {
if($this->payload['event'] === 'bind') {
$query['bind_code'] = $this->request->param('code');
}else {
$query['login_code'] = $this->request->param('code');
}
return [
'redirect_url' => $this->payload['page'] . '?' . http_build_query($query)
];
} else {
$query = [
'platform' => 'officialAccount',
'payload' => urlencode(json_encode($this->payload))
];
$loginUrl = $this->request->domain() . '/addons/shopro/third.wechat/oauthLogin?' . http_build_query($query);
return [
'login_url' => $this->wechat->oauth->scopes(['snsapi_userinfo'])->redirect($loginUrl)->getTargetUrl()
];
}
}
public function jssdk($APIs)
{
$this->wechat->jssdk->setUrl($this->payload['url']);
return $this->wechat->jssdk->buildConfig($APIs, false, false, false);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace addons\shopro\service\third\wechat;
use fast\Http;
use addons\shopro\facade\Wechat;
class OpenPlatform
{
public $wechat;
protected $request;
protected $payload;
public function __construct($payload)
{
$this->payload = $payload;
$this->request = request();
$this->wechat = Wechat::openPlatform();
}
public function login()
{
$payload = $this->payload;
if (empty($payload['code'])) {
error_stop('登陆失败');
}
$config = sheep_config('shop.platform.App');
// 获取accessToken & openid
$res = Http::get('https://api.weixin.qq.com/sns/oauth2/access_token', [
'appid' => $config['app_id'],
'secret' => $config['secret'],
'code' => $payload['code'],
'grant_type' => 'authorization_code'
]);
$decryptedData = json_decode($res, true);
if (isset($decryptedData['errmsg'])) {
error_stop($decryptedData['errmsg']);
}
// 获取userInfo
$res = Http::get('https://api.weixin.qq.com/sns/userinfo', ['access_token' => $decryptedData['access_token'], 'openid' => $decryptedData['openid']]);
$userInfo = is_string($res) ? json_decode($res, true) : $res;
if (isset($userInfo['errmsg'])) {
error_stop($userInfo['errmsg']);
}
$wechatUser = [
'openid' => $userInfo['openid'],
'unionid' => $userInfo['unionid'] ?? '',
'avatar' => $userInfo['headimgurl'],
'nickname' => $userInfo['nickname'],
];
return $wechatUser;
}
public function bind()
{
return $this->login();
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace addons\shopro\service\third\wechat;
use app\common\library\Auth;
use addons\shopro\service\user\UserAuth;
use app\admin\model\shopro\ThirdOauth;
use app\admin\model\shopro\user\User as UserModel;
class Wechat
{
// 平台
protected $platform;
// 转发服务
protected $service;
public function __construct($platform, $payload = [])
{
$this->platform = $platform;
$this->service = $this->setPlatformService($payload);
}
public function getApp()
{
return $this->service->wechat;
}
/**
* 微信登陆
*
* @return array
*/
public function login()
{
$wechatUser = $this->service->login();
$oauthInfo = $this->createOrUpdateOauthInfo($wechatUser);
$this->registerOrBindUser($oauthInfo, 0, ['mobile' => $wechatUser['mobile'] ?? '']);
$oauthInfo->save();
$auth = Auth::instance();
$ret = $auth->direct($oauthInfo->user_id);
if ($ret) {
$oauthInfo->login_num += 1;
set_token_in_header($auth->getToken());
return true;
} else {
$oauthInfo->user_id = 0;
$oauthInfo->save();
return false;
}
}
/**
* 微信绑定
*
* @return array
*/
public function bind(Object $user)
{
$wechatUser = $this->service->bind();
$oauthInfo = $this->createOrUpdateOauthInfo($wechatUser);
if ($this->registerOrBindUser($oauthInfo, $user->id)) {
return true;
}
return false;
}
/**
* 微信解绑
*
* @return array
*/
public function unbind()
{
$user = auth_user();
if (!$user->verification->mobile) {
error_stop('请先绑定手机号后再进行操作');
}
$oauthInfo = ThirdOauth::where([
'user_id' => $user->id,
'platform' => $this->platform,
'provider' => 'wechat'
])->find();
if ($oauthInfo) {
$oauthInfo->delete();
return true;
}
return false;
}
/**
* 创建/更新用户认证信息
*
* @return think\Model
*/
private function createOrUpdateOauthInfo($wechatUser, $extend = [])
{
$oauthInfo = ThirdOauth::getByOpenid($wechatUser['openid']);
if (!$oauthInfo) { // 创建新的third_oauth条目
$wechatUser['user_id'] = 0;
if (!empty($wechatUser['unionid'])) { // unionid账号合并策略
$unionOauthInfo = ThirdOauth::getByUnionid($wechatUser['unionid']);
if ($unionOauthInfo) {
$wechatUser['user_id'] = $unionOauthInfo->user_id;
}
}
$wechatUser['provider'] = 'wechat';
$wechatUser['platform'] = $this->platform;
$wechatUser = array_merge($wechatUser, $extend);
$thirdOauth = new ThirdOauth($wechatUser);
$thirdOauth->allowField(true)->save();
$oauthInfo = ThirdOauth::getByOpenid($wechatUser['openid']);
} else { // 更新授权信息
if ($this->platform === 'miniProgram') {
unset($wechatUser['avatar']);
unset($wechatUser['nickname']);
}
$oauthInfo->allowField(true)->save($wechatUser);
}
return $oauthInfo;
}
/**
* 注册/绑定用户
*
* @return think\Model
*/
private function registerOrBindUser($oauthInfo, $user_id = 0, $extend = [])
{
// 检查用户存在
if ($oauthInfo->user_id) {
$user = UserModel::get($oauthInfo->user_id);
if ($user && $user_id > 0) {
error_stop('该微信账号已绑定其他用户');
}
// 用户被删除,则重置第三方信息所绑定的用户id
if (!$user) {
$oauthInfo->user_id = 0;
}
}
// 绑定用户
if ($oauthInfo->user_id === 0 && $user_id > 0) {
$user = UserModel::get($user_id);
if ($user) {
$oauthInfo->user_id = $user_id;
return $oauthInfo->save();
} else {
error_stop('该用户暂不可绑定微信账号');
}
return false;
}
// 注册新用户
if ($oauthInfo->user_id === 0 && $user_id === 0) {
$auth = (new UserAuth())->register([
'nickname' => $oauthInfo->nickname ?? '',
'avatar' => $oauthInfo->avatar ?? '',
'mobile' => $extend['mobile'] ?? ''
]);
$user = $auth->getUser();
$oauthInfo->user_id = $user->id;
return $oauthInfo->save();
}
}
/**
* 设置平台服务类
*
* @return class
*/
private function setPlatformService($payload)
{
switch ($this->platform) {
case 'officialAccount':
$service = new OfficialAccount($payload);
break;
case 'miniProgram':
$service = new MiniProgram($payload);
break;
case 'openPlatform':
$service = new OpenPlatform($payload);
break;
}
if (!isset($service)) error_stop('平台参数有误');
return $service;
}
/**
* 方法转发到驱动提供者
*
* @param string $funcname
* @param array $arguments
* @return void
*/
public function __call($funcname, $arguments)
{
return $this->service->{$funcname}(...$arguments);
}
}