feat : login wx

This commit is contained in:
2024-11-11 17:04:10 +08:00
parent 83a38d5001
commit 3a5739ee19
20 changed files with 844 additions and 4 deletions

View File

@@ -0,0 +1,52 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api;
use App\Lib\ApiReturn;
use Hyperf\Context\Context;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
abstract class BaseService
{
/**
* 请求对象
* @var RequestInterface
*/
#[Inject]
protected RequestInterface $request;
/**
* 通用返回对象
* @var ApiReturn $return
*/
#[Inject]
protected ApiReturn $return;
/**
* 用户id
* @var int $userId
*/
protected int $userId = 0;
/**
* 主构造函数(获取请求对象)
*/
public function __construct()
{
$this->userId = Context::get("user_id",0);
}
/**
* 主体函数抽象类
*/
abstract public function handle();
}

View File

@@ -0,0 +1,164 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Login;
use App\Cache\Redis\Api\ApiRedisKey;
use App\Cache\Redis\RedisCache;
use App\Constants\Common\UserCode;
use App\Exception\ApiException;
use App\Extend\StringUtil;
use App\Extend\SystemUtil;
use App\Lib\Crypto\CryptoFactory;
use App\Model\User;
use App\Model\UserThird;
use App\Service\Api\BaseService;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
abstract class LoginBaseService extends BaseService
{
/**
* 注入缓存类
* @var RedisCache
*/
#[Inject]
protected RedisCache $redis;
/**
* 注入加密工厂
* @var CryptoFactory
*/
#[Inject]
protected CryptoFactory $cryptoFactory;
/**
* 注入三方用户
* @var UserThird
*/
#[Inject]
protected UserThird $userThirdModel;
/**
* 锁定注册
* @var string
*/
protected string $lockKey;
/**
* 登录code login_type = wx_login 必填
* @var string
*/
protected string $jsCode = '';
/**
* 手机号 login_type = mobile_code 必填
* @var string
*/
protected string $mobile = '';
/**
* 获取的用户信息
* @var
*/
protected mixed $userInfo;
/**
* @var string
*/
protected string $openId = '';
/**
* @var string
*/
protected string $unionId = '';
/**
* 登录
* @return void
*/
protected function login(): void
{
$this->userId = empty($this->userId) ? $this->userInfo->id : $this->userId;
if (empty($this->userId)) {
throw new ApiException('登录失败');
}
//todo 判断注销 判断封号
//todo 更新登录时间
}
/**
* 返回值
* @return array
* @throws \Exception
*/
protected function getReturn():array
{
$loginReturn = [
'id' => $this->userId,
'is_bind_mobile' => $this->userInfo->mobile ? UserCode::IS_BIND_PHONE : UserCode::IS_NOT_BIND_PHONE,
'nickName' => $this->userInfo->nickName,
'is_default_avatar' => $this->userInfo->avatar_id == 0 ? UserCode::IS_DEFAULT_AVATAR : UserCode::IS_NOT_DEFAULT_AVATAR,
];
$loginReturn['token'] = $this->cryptoFactory->cryptoClass('jwt', json_encode($loginReturn))->encrypt();
return $loginReturn;
}
/**
* 判断是不是没有加锁
* @param $type
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \RedisException
*/
protected function checkLock($type): void
{
$this->lockKey = match ($type){
1 => ApiRedisKey::LoginAndRegisterByMobileLock($this->mobile),
2 => ApiRedisKey::LoginAndRegisterByCodeLock($this->jsCode)
};
if (0 == ($this->redis->addLock($this->lockKey))){
throw new ApiException('请勿重复点击');
}
}
/**
* 添加用户
* @return void
*/
protected function addUser(): void
{
$model = new User();
//默认头像和默认名称
$model->nickname = '用户'.StringUtil::randStr(6);
$model->avatar_id = 0;
$model->reg_ip = SystemUtil::getClientIp();
if (!$model->save()) throw new ApiException('数据保存失败-注册失败');
$this->userId = $model->id;
$this->userInfo = $model;
}
abstract protected function register();
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Login;
use App\Exception\AdminException;
use App\Service\Api\BaseService;
class LoginService extends BaseService
{
protected string $loginType = '';
public function handle()
{
$this->loginType = $this->request->input('login_type','');
$factory = new LoginTypeFactory();
$service = match ($this->request->input('login_type',''))
{
'wx_login' => $factory->wxFastLogin(),
'mobile_code' => $factory->mobileCodeLogin(),
default => throw new AdminException('登录类型错误'),
};
$loginInfo = $service->handle();
return $this->return->success('登录成功',$loginInfo);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Login;
class LoginTypeFactory
{
/**
* 验证码登录
* @return MobileCodeLoginService
*/
public function mobileCodeLogin(): MobileCodeLoginService
{
return new MobileCodeLoginService();
}
/**
* 微信快速组件登录
* @return WxFastLoginService
*/
public function wxFastLogin(): WxFastLoginService
{
return new WxFastLoginService();
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Login;
class MobileCodeLoginService extends LoginBaseService
{
public function handle()
{
return [];
}
protected function register() {}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Login;
use App\Exception\ApiException;
use App\Model\UserThird;
use App\Service\ServiceTrait\Api\WxMiniTrait;
use Hyperf\DbConnection\Db;
class WxFastLoginService extends LoginBaseService
{
use WxMiniTrait;
/**
* 登录类型 2=微信小程序
*/
const int LOGIN_TYPE = 2;
public function handle()
{
$this->jsCode = $this->request->input('js_code');
if (empty($this->jsCode)) throw new ApiException('登录参数错误');
$wxInfo = $this->jsCodeGetOpenId($this->jsCode);
$this->openId = $wxInfo['openid'];
$this->unionId = $wxInfo['unionid'];
$this->checkLock(self::LOGIN_TYPE);
$this->register();
$this->login();
$this->redis->delLock($this->lockKey);
return $this->getReturn();
}
protected function register(): void
{
$thirdInfo = $this->userThirdModel->getThirdInfoByOpenId($this->openId);
if (!empty($thirdInfo)) {
$this->userId = $thirdInfo->user_id;
return;
}
// todo 设备封禁不可注册 注册限制
Db::transaction(function () {
$this->addUser();
$this->addUserThird();
//todo 要不要生成邀请码 有没有注册奖励
});
}
/**
* @return void
*/
private function addUserThird(): void
{
$model = new UserThird();
$model->user_id = $this->userId;
$model->open_id = $this->openId;
$model->union_id = $this->unionId;
if (!$model->save()) throw new ApiException('注册失败-00001');
}
}