init
- 框架初始化 - 安装插件 - 修复PHP8.4报错
This commit is contained in:
132
addons/shopro/service/third/wechat/MiniProgram.php
Normal file
132
addons/shopro/service/third/wechat/MiniProgram.php
Normal 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];
|
||||
}
|
||||
}
|
||||
77
addons/shopro/service/third/wechat/OfficialAccount.php
Normal file
77
addons/shopro/service/third/wechat/OfficialAccount.php
Normal 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);
|
||||
}
|
||||
}
|
||||
62
addons/shopro/service/third/wechat/OpenPlatform.php
Normal file
62
addons/shopro/service/third/wechat/OpenPlatform.php
Normal 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();
|
||||
}
|
||||
}
|
||||
210
addons/shopro/service/third/wechat/Wechat.php
Normal file
210
addons/shopro/service/third/wechat/Wechat.php
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user