607 lines
19 KiB
PHP
Executable File
607 lines
19 KiB
PHP
Executable File
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | likeadmin快速开发前后端分离管理后台(PHP版)
|
||
// +----------------------------------------------------------------------
|
||
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
|
||
// | 开源版本可自由商用,可去除界面版权logo
|
||
// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
|
||
// | github下载:https://github.com/likeshop-github/likeadmin
|
||
// | 访问官网:https://www.likeadmin.cn
|
||
// | likeadmin团队 版权所有 拥有最终解释权
|
||
// +----------------------------------------------------------------------
|
||
// | author: likeadminTeam
|
||
// +----------------------------------------------------------------------
|
||
|
||
namespace app\api\logic;
|
||
|
||
use Alipay\EasySDK\Kernel\Factory;
|
||
use app\api\cache\TokenCache;
|
||
use app\api\service\UserServer;
|
||
use app\common\cache\WebScanLoginCache;
|
||
use app\common\logic\AccountLogLogic;
|
||
use app\common\logic\BaseLogic;
|
||
use app\common\model\account\AccountLog;
|
||
use app\common\model\Client_;
|
||
use app\common\service\WeChatServer;
|
||
use app\common\service\ConfigServer;
|
||
use EasyWeChat\Kernel\Exceptions\Exception;
|
||
use app\api\service\{UserTokenService, WechatUserService};
|
||
use app\common\enum\{LoginEnum, user\UserTerminalEnum, YesNoEnum};
|
||
use app\common\service\{
|
||
ConfigService,
|
||
FileService,
|
||
wechat\WeChatConfigService,
|
||
wechat\WeChatMnpService,
|
||
wechat\WeChatOaService,
|
||
wechat\WeChatRequestService
|
||
};
|
||
use app\common\model\user\{User, UserAuth};
|
||
use think\facade\{Cache, Db, Config};
|
||
|
||
/**
|
||
* 登录逻辑
|
||
* Class LoginLogic
|
||
* @package app\api\logic
|
||
*/
|
||
class LoginLogic extends BaseLogic
|
||
{
|
||
|
||
/**
|
||
* @notes 账号密码注册
|
||
* @param array $params
|
||
* @return bool
|
||
* @author 段誉
|
||
* @date 2022/9/7 15:37
|
||
*/
|
||
public static function register(array $params)
|
||
{
|
||
try {
|
||
$userSn = User::createUserSn();
|
||
$passwordSalt = Config::get('project.unique_identification');
|
||
$password = create_password($params['password'], $passwordSalt);
|
||
$avatar = ConfigService::get('default_image', 'user_avatar');
|
||
|
||
User::create([
|
||
'sn' => $userSn,
|
||
'avatar' => $avatar,
|
||
'nickname' => '用户' . $userSn,
|
||
'account' => $params['account'],
|
||
'password' => $password,
|
||
'channel' => $params['channel'],
|
||
]);
|
||
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
self::setError($e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 账号/手机号登录,手机号验证码
|
||
* @param $params
|
||
* @return array|false
|
||
* @author 段誉
|
||
* @date 2022/9/6 19:26
|
||
*/
|
||
public static function login($params)
|
||
{
|
||
try {
|
||
// 账号/手机号 密码登录
|
||
$where = ['account|mobile' => $params['account']];
|
||
if ($params['scene'] == LoginEnum::MOBILE_CAPTCHA) {
|
||
//手机验证码登录
|
||
$where = ['mobile' => $params['account']];
|
||
}
|
||
|
||
$user = User::where($where)->findOrEmpty();
|
||
if ($user->isEmpty()) {
|
||
throw new \Exception('用户不存在');
|
||
}
|
||
|
||
//更新登录信息
|
||
$user->login_time = time();
|
||
$user->login_ip = request()->ip();
|
||
$user->save();
|
||
|
||
//设置token
|
||
$userInfo = UserTokenService::setToken($user->id, $params['terminal']);
|
||
|
||
//返回登录信息
|
||
$avatar = $user->avatar ?: Config::get('project.default_image.user_avatar');
|
||
$avatar = FileService::getFileUrl($avatar);
|
||
|
||
return [
|
||
'nickname' => $userInfo['nickname'],
|
||
'sn' => $userInfo['sn'],
|
||
'mobile' => $userInfo['mobile'],
|
||
'avatar' => $avatar,
|
||
'token' => $userInfo['token'],
|
||
];
|
||
} catch (\Exception $e) {
|
||
self::setError($e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
public static function authLogin($post)
|
||
{
|
||
try {
|
||
//通过code获取微信 openid
|
||
$response = self::getWechatResByCode($post);
|
||
$response['headimgurl'] = $post['headimgurl'] ?? '';
|
||
$response['nickname'] = $post['nickname'] ?? '';
|
||
//通过获取到的openID或unionid获取当前 系统 用户id
|
||
$user_id = self::getUserByWechatResponse($response);
|
||
|
||
} catch (Exception $e) {
|
||
self::setError('登录失败:' . $e->getMessage());
|
||
return false;
|
||
} catch (\think\Exception $e) {
|
||
self::setError('登录失败:' . $e->getMessage());
|
||
return false;
|
||
}
|
||
|
||
if (empty($user_id)) {
|
||
$user_info = UserServer::createUser($response, Client_::mnp);
|
||
} else {
|
||
$user_info = UserServer::updateUser($response, Client_::mnp, $user_id);
|
||
}
|
||
|
||
//验证用户信息
|
||
$check_res = self::checkUserInfo($user_info);
|
||
if (true !== $check_res) {
|
||
return self::setError($check_res);
|
||
|
||
}
|
||
|
||
//创建会话
|
||
$user_info['token'] = self::createSession($user_info['id'], Client_::mnp);
|
||
|
||
unset($user_info['id'], $user_info['disable']);
|
||
return $user_info;
|
||
}
|
||
public static function registerAward($user_id){
|
||
$register_award_integral_status = ConfigServer::get('marketing','register_award_integral_status',0);
|
||
$register_award_coupon_status = ConfigServer::get('marketing','register_award_coupon_status',0);
|
||
//赠送积分
|
||
if($register_award_integral_status){
|
||
$register_award_integral = ConfigServer::get('marketing','register_award_integral',0);
|
||
//赠送的积分
|
||
if($register_award_integral > 0){
|
||
\think\Db::name('user')->where(['id'=>$user_id])->setInc('user_integral',$register_award_integral);
|
||
AccountLogLogic::AccountRecord($user_id,$register_award_integral,1,AccountLog::register_add_integral,'');
|
||
}
|
||
}
|
||
//注册账号,首次进入首页时领取优惠券
|
||
$register_award_coupon = ConfigServer::get('marketing','register_award_coupon','');
|
||
if($register_award_coupon_status && $register_award_coupon){
|
||
Cache::tag('register_coupon')->set('register_coupon_'.$user_id,$register_award_coupon);
|
||
}
|
||
//会员等级
|
||
$user_level = Db::name('user_level')->where(['del'=>0,'growth_value'=>0])->find();
|
||
if($user_level){
|
||
Db::name('user')->where(['id'=>$user_id])->update(['level'=>$user_level['id']]);
|
||
}
|
||
}
|
||
/**
|
||
* Notes: 根据code 获取微信信息(openid, unionid)
|
||
* @param $post
|
||
* @author 段誉(2021/4/19 16:52)
|
||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||
* @throws Exception
|
||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||
*/
|
||
public static function getWechatResByCode($post)
|
||
{
|
||
// $config = WeChatServer::getMnpConfig();
|
||
$response = (new WeChatMnpService())->getMnpResByCode($post['code']);
|
||
// $app = Factory::miniProgram($config);
|
||
// $response = $app->auth->session($post['code']);
|
||
if (!isset($response['openid']) || empty($response['openid'])) {
|
||
throw new Exception('获取openID失败');
|
||
}
|
||
return $response;
|
||
}
|
||
/**
|
||
* Notes: 根据微信返回信息查询当前用户id
|
||
* @param $response
|
||
* @author 段誉(2021/4/19 16:52)
|
||
* @return mixed
|
||
*/
|
||
public static function getUserByWechatResponse($response)
|
||
{
|
||
$user_id = Db::name('user_auth au')
|
||
->join('user u', 'au.user_id=u.id')
|
||
->where(['u.del' => 0])
|
||
->where(function ($query) use ($response) {
|
||
$query->whereOr(['au.openid' => $response['openid']]);
|
||
if(isset($response['unionid']) && !empty($response['unionid'])){
|
||
$query->whereOr(['au.unionid' => $response['unionid']]);
|
||
}
|
||
})
|
||
->value('user_id');
|
||
return $user_id;
|
||
}
|
||
public static function checkUserInfo($user_info)
|
||
{
|
||
if (empty($user_info)) {
|
||
return '登录失败:user';
|
||
}
|
||
|
||
if ($user_info['disable']) {
|
||
return '账号已被禁用';
|
||
}
|
||
|
||
return true;
|
||
}
|
||
/**
|
||
* 创建会话
|
||
* @param $user_id
|
||
* @param $client
|
||
* @return string
|
||
* @throws \think\Exception
|
||
* @throws \think\db\exception\DataNotFoundException
|
||
* @throws \think\db\exception\ModelNotFoundException
|
||
* @throws \think\exception\DbException
|
||
* @throws \think\exception\PDOException
|
||
*/
|
||
public static function createSession($user_id, $client)
|
||
{
|
||
|
||
//清除之前缓存
|
||
$token = Db::name('session')
|
||
->where(['user_id' => $user_id, 'client' => $client])
|
||
->value('token');
|
||
if($token) {
|
||
$token_cache = new TokenCache($token);
|
||
$token_cache->del();
|
||
}
|
||
|
||
$result = Db::name('session')
|
||
->where(['user_id' => $user_id, 'client' => $client])
|
||
->find();
|
||
|
||
$time = time();
|
||
$expire_time = $time + Config::get('project.token_expire_time');
|
||
$token = md5($user_id . $client . $time);
|
||
$data = [
|
||
'user_id' => $user_id,
|
||
'token' => $token,
|
||
'client' => $client,
|
||
'update_time' => $time,
|
||
'expire_time' => $expire_time,
|
||
];
|
||
|
||
if (empty($result)) {
|
||
Db::name('session')->insert($data);
|
||
} else {
|
||
Db::name('session')
|
||
->where(['user_id' => $user_id, 'client' => $client])
|
||
->update($data);
|
||
}
|
||
|
||
//更新登录信息
|
||
$login_ip = $ip = request()->ip();
|
||
Db::name('user')
|
||
->where(['id' => $user_id])
|
||
->update(['login_time' => $time, 'login_ip' => $login_ip]);
|
||
|
||
//创建新的缓存
|
||
(new TokenCache($token, ['token' => $token]))->set(300);
|
||
return $token;
|
||
}
|
||
/**
|
||
* @notes 退出登录
|
||
* @param $userInfo
|
||
* @return bool
|
||
* @throws \think\db\exception\DataNotFoundException
|
||
* @throws \think\db\exception\DbException
|
||
* @throws \think\db\exception\ModelNotFoundException
|
||
* @author 段誉
|
||
* @date 2022/9/16 17:56
|
||
*/
|
||
public static function logout($userInfo)
|
||
{
|
||
//token不存在,不注销
|
||
if (!isset($userInfo['token'])) {
|
||
return false;
|
||
}
|
||
|
||
//设置token过期
|
||
return UserTokenService::expireToken($userInfo['token']);
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 获取微信请求code的链接
|
||
* @param string $url
|
||
* @return string
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:47
|
||
*/
|
||
public static function codeUrl(string $url)
|
||
{
|
||
return (new WeChatOaService())->getCodeUrl($url);
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 公众号登录
|
||
* @param array $params
|
||
* @return array|false
|
||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:47
|
||
*/
|
||
public static function oaLogin(array $params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
//通过code获取微信 openid
|
||
$response = (new WeChatOaService())->getOaResByCode($params['code']);
|
||
$userServer = new WechatUserService($response, UserTerminalEnum::WECHAT_OA);
|
||
$userInfo = $userServer->getResopnseByUserInfo()->authUserLogin()->getUserInfo();
|
||
|
||
// 更新登录信息
|
||
self::updateLoginInfo($userInfo['id']);
|
||
|
||
Db::commit();
|
||
return $userInfo;
|
||
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 小程序-静默登录
|
||
* @param array $params
|
||
* @return array|false
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:47
|
||
*/
|
||
public static function silentLogin(array $params)
|
||
{
|
||
try {
|
||
//通过code获取微信 openid
|
||
$response = (new WeChatMnpService())->getMnpResByCode($params['code']);
|
||
$userServer = new WechatUserService($response, UserTerminalEnum::WECHAT_MMP);
|
||
$userInfo = $userServer->getResopnseByUserInfo('silent')->getUserInfo();
|
||
|
||
if (!empty($userInfo)) {
|
||
// 更新登录信息
|
||
self::updateLoginInfo($userInfo['id']);
|
||
}
|
||
|
||
return $userInfo;
|
||
} catch (\Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 小程序-授权登录
|
||
* @param array $params
|
||
* @return array|false
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:47
|
||
*/
|
||
public static function mnpLogin(array $params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
//通过code获取微信 openid
|
||
$response = (new WeChatMnpService())->getMnpResByCode($params['code']);
|
||
$userServer = new WechatUserService($response, UserTerminalEnum::WECHAT_MMP);
|
||
$userInfo = $userServer->getResopnseByUserInfo()->authUserLogin()->getUserInfo();
|
||
|
||
// 更新登录信息
|
||
self::updateLoginInfo($userInfo['id']);
|
||
|
||
Db::commit();
|
||
return $userInfo;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 更新登录信息
|
||
* @param $userId
|
||
* @throws \Exception
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:46
|
||
*/
|
||
public static function updateLoginInfo($userId)
|
||
{
|
||
$user = User::findOrEmpty($userId);
|
||
if ($user->isEmpty()) {
|
||
throw new \Exception('用户不存在');
|
||
}
|
||
|
||
$time = time();
|
||
$user->login_time = $time;
|
||
$user->login_ip = request()->ip();
|
||
$user->update_time = $time;
|
||
$user->save();
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 小程序端绑定微信
|
||
* @param array $params
|
||
* @return bool
|
||
* @author 段誉
|
||
* @date 2022/9/20 19:46
|
||
*/
|
||
public static function mnpAuthLogin(array $params)
|
||
{
|
||
try {
|
||
//通过code获取微信openid
|
||
$response = (new WeChatMnpService())->getMnpResByCode($params['code']);
|
||
$response['user_id'] = $params['user_id'];
|
||
$response['terminal'] = UserTerminalEnum::WECHAT_MMP;
|
||
|
||
return self::createAuth($response);
|
||
|
||
} catch (\Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 公众号端绑定微信
|
||
* @param array $params
|
||
* @return bool
|
||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||
* @author 段誉
|
||
* @date 2022/9/16 10:43
|
||
*/
|
||
public static function oaAuthLogin(array $params)
|
||
{
|
||
try {
|
||
//通过code获取微信openid
|
||
$response = (new WeChatOaService())->getOaResByCode($params['code']);
|
||
$response['user_id'] = $params['user_id'];
|
||
$response['terminal'] = UserTerminalEnum::WECHAT_OA;
|
||
|
||
return self::createAuth($response);
|
||
|
||
} catch (\Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 生成授权记录
|
||
* @param $response
|
||
* @return bool
|
||
* @throws \Exception
|
||
* @author 段誉
|
||
* @date 2022/9/16 10:43
|
||
*/
|
||
public static function createAuth($response)
|
||
{
|
||
//先检查openid是否有记录
|
||
$isAuth = UserAuth::where('openid', '=', $response['openid'])->findOrEmpty();
|
||
if (!$isAuth->isEmpty()) {
|
||
throw new \Exception('该微信已被绑定');
|
||
}
|
||
|
||
if (isset($response['unionid']) && !empty($response['unionid'])) {
|
||
//在用unionid找记录,防止生成两个账号,同个unionid的问题
|
||
$userAuth = UserAuth::where(['unionid' => $response['unionid']])
|
||
->findOrEmpty();
|
||
if (!$userAuth->isEmpty() && $userAuth->user_id != $response['user_id']) {
|
||
throw new \Exception('该微信已被绑定');
|
||
}
|
||
}
|
||
|
||
//如果没有授权,直接生成一条微信授权记录
|
||
UserAuth::create([
|
||
'user_id' => $response['user_id'],
|
||
'openid' => $response['openid'],
|
||
'unionid' => $response['unionid'] ?? '',
|
||
'terminal' => $response['terminal'],
|
||
]);
|
||
return true;
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 获取扫码登录地址
|
||
* @return array|false
|
||
* @author 段誉
|
||
* @date 2022/10/20 18:23
|
||
*/
|
||
public static function getScanCode($redirectUri)
|
||
{
|
||
try {
|
||
$config = WeChatConfigService::getOpConfig();
|
||
$appId = $config['app_id'];
|
||
$redirectUri = UrlEncode($redirectUri);
|
||
|
||
// 设置有效时间标记状态, 超时扫码不可登录
|
||
$state = MD5(time().rand(10000, 99999));
|
||
(new WebScanLoginCache())->setScanLoginState($state);
|
||
|
||
// 扫码地址
|
||
$url = WeChatRequestService::getScanCodeUrl($appId, $redirectUri, $state);
|
||
return ['url' => $url];
|
||
|
||
} catch (\Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 网站扫码登录
|
||
* @param $params
|
||
* @return array|false
|
||
* @author 段誉
|
||
* @date 2022/10/21 10:28
|
||
*/
|
||
public static function scanLogin($params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
// 通过code 获取 access_token,openid,unionid等信息
|
||
$userAuth = WeChatRequestService::getUserAuthByCode($params['code']);
|
||
|
||
if (empty($userAuth['openid']) || empty($userAuth['access_token'])) {
|
||
throw new \Exception('获取用户授权信息失败');
|
||
}
|
||
|
||
// 获取微信用户信息
|
||
$response = WeChatRequestService::getUserInfoByAuth($userAuth['access_token'], $userAuth['openid']);
|
||
|
||
// 生成用户或更新用户信息
|
||
$userServer = new WechatUserService($response, UserTerminalEnum::PC);
|
||
$userInfo = $userServer->getResopnseByUserInfo()->authUserLogin()->getUserInfo();
|
||
|
||
// 更新登录信息
|
||
self::updateLoginInfo($userInfo['id']);
|
||
|
||
Db::commit();
|
||
return $userInfo;
|
||
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 更新用户信息
|
||
* @param $params
|
||
* @param $userId
|
||
* @return User
|
||
* @author 段誉
|
||
* @date 2023/2/22 11:19
|
||
*/
|
||
public static function updateUser($params, $userId)
|
||
{
|
||
return User::where(['id' => $userId])->update([
|
||
'nickname' => $params['nickname'],
|
||
'avatar' => FileService::setFileUrl($params['avatar']),
|
||
'is_new_user' => YesNoEnum::NO
|
||
]);
|
||
}
|
||
} |