639 lines
22 KiB
PHP
639 lines
22 KiB
PHP
<?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 app\common\cache\WebScanLoginCache;
|
||
use app\common\logic\BaseLogic;
|
||
use app\api\service\{UserTokenService, WechatUserService};
|
||
use app\common\enum\{LoginEnum, user\UserTerminalEnum, YesNoEnum};
|
||
use app\common\model\dict\DictData;
|
||
use app\common\service\{
|
||
ConfigService,
|
||
FileService,
|
||
wechat\WeChatConfigService,
|
||
wechat\WeChatMnpService,
|
||
wechat\WeChatOaService,
|
||
wechat\WeChatRequestService
|
||
};
|
||
use app\common\model\user\{User, UserAuth};
|
||
use think\facade\{Db, Config};
|
||
use Firebase\JWT\JWT;
|
||
use Firebase\JWT\Key;
|
||
use Firebase\JWT\SignatureInvalidException;
|
||
use Firebase\JWT\BeforeValidException;
|
||
use Firebase\JWT\ExpiredException;
|
||
use GuzzleHttp\Client;
|
||
use GuzzleHttp\Psr7\Request;
|
||
use GuzzleHttp\Exception\GuzzleException;
|
||
use Guzzle\Http\Exception\RequestException;
|
||
/**
|
||
* 登录逻辑
|
||
* 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 {
|
||
// 手机号已被使用
|
||
$mobileUser = User::where(['account' => $params['account']])->find();
|
||
if (!empty($mobileUser)) {
|
||
self::setError('手机号已被注册');
|
||
return false;
|
||
}
|
||
$count = User::where('company_id', $params['company_id'])->count();
|
||
$value = DictData::where('id', 28)->value('value');
|
||
if ($count >= $value) {
|
||
self::setError('你创建的账号已达上限');
|
||
return false;
|
||
}
|
||
$userSn = User::createUserSn();
|
||
$passwordSalt = Config::get('project.unique_identification');
|
||
$password = create_password($params['password'], $passwordSalt);
|
||
// if($params['qualification']){
|
||
// $params['qualification']=explode(',',$params['qualification']);
|
||
// }
|
||
if ($params['avatar'] != '') {
|
||
$avatar = $params['avatar'];
|
||
} else {
|
||
$avatar = ConfigService::get('default_image', 'user_avatar');
|
||
}
|
||
$group_id=1;
|
||
if ($params['is_captain']) {
|
||
$group_id=2;
|
||
}
|
||
// 镇农科公司服务部长
|
||
if ($params['is_service_manager'] == 1) {
|
||
$user = User::where(['company_id' => $params['company_id'], 'group_id' => 14])->find();
|
||
if (!empty($user)) {
|
||
self::setError('公司已创建服务部长账号');
|
||
return false;
|
||
}
|
||
$group_id=14;
|
||
}
|
||
User::create([
|
||
'sn' => $userSn,
|
||
'avatar' => $avatar,
|
||
'is_captain' => $params['is_captain'],
|
||
'nickname' => $params['nickname'],
|
||
'account' => $params['account'],
|
||
'mobile' => $params['account'],
|
||
'id_card' => $params['id_card'],
|
||
'password' => $password,
|
||
'channel' => 0,
|
||
'sex' => $params['sex'],
|
||
'province' => $params['province'],
|
||
'city' => $params['city'],
|
||
'area' => $params['area'],
|
||
'street' => $params['street'],
|
||
'village' => $params['village'],
|
||
'brigade' => $params['brigade'],
|
||
'address' => $params['address'],
|
||
'qualification' => json_encode($params['qualification']),
|
||
'company_id' => $params['company_id'],
|
||
'group_id' => $group_id,
|
||
]);
|
||
|
||
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('用户不存在');
|
||
}
|
||
if (isset($params['register_id']) && $params['register_id'] != '') {
|
||
$user->register_id = $params['register_id'];
|
||
}
|
||
if (isset($params['ytj_register_id']) && $params['ytj_register_id'] != '') {
|
||
$user->ytj_register_id = $params['ytj_register_id'];
|
||
}
|
||
//更新登录信息
|
||
$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);
|
||
if(isset($params['shop_token'])&&$params['shop_token']!=''){
|
||
$jwt = JWT::decode($params['shop_token'], new Key('ae47e94a7dcd1fdfacb499b60e361a8d', 'HS256'));
|
||
if ($jwt) {
|
||
$user_id = $jwt->jti[0];
|
||
Db::name('user_other')->insert(['user_id'=>$user->id,'other_user_id'=>$user_id,'type'=>'shop_user']);
|
||
}
|
||
}
|
||
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 shop($payload,$type=1){
|
||
$jwt = JWT::decode($payload, new Key('ae47e94a7dcd1fdfacb499b60e361a8d', 'HS256'));
|
||
if ($jwt) {
|
||
$user_id = $jwt->jti[0];
|
||
$find = Db::name('user_other')->where('other_user_id', $user_id)->where('type', 'shop_user')->find();
|
||
if ($find) {
|
||
$user = User::where('id', $find['user_id'])->findOrEmpty();
|
||
if ($user->isEmpty()) {
|
||
self::setError('无登录信息');
|
||
return false;
|
||
}
|
||
$terminal=3;
|
||
$Android=IndexLogic::isAndroid();
|
||
if($Android){
|
||
$terminal=5;
|
||
}
|
||
$ios=IndexLogic::isIOS();
|
||
if($ios){
|
||
$terminal=6;
|
||
}
|
||
$userInfo = UserTokenService::setToken($user->id, $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'],
|
||
];
|
||
}
|
||
}
|
||
self::setError('无登录信息');
|
||
return false;
|
||
}
|
||
|
||
public static function parseToken($token){
|
||
$app_key = 'ae47e94a7dcd1fdfacb499b60e361a8d';
|
||
try {
|
||
JWT::$leeway = 10; //当前时间减去10秒,时间留点余地
|
||
$decoded = JWT::decode($token, new Key($app_key, 'HS256'));
|
||
$decodedArray = json_decode(json_encode($decoded), true);
|
||
$jwtData = $decodedArray['data'] ?? [];
|
||
if (empty($jwtData['uid']) || empty($jwtData['phone'])) {
|
||
self::setError('当前账号未授权,请手动登录');
|
||
return false;
|
||
}
|
||
$where = ['account|mobile' => $jwtData['phone']];
|
||
$user = User::where($where)->findOrEmpty();
|
||
if ($user->isEmpty()) {
|
||
try {
|
||
//适配解析商城token
|
||
$parseHostUrl = env('url.shop_prefix') . '/api/parse/token';
|
||
$client = new Client(['timeout' => 5]);
|
||
$requestBody['token'] = $token;
|
||
$response = $client->request('POST', $parseHostUrl, [
|
||
'json' => $requestBody,
|
||
'verify' => false
|
||
]);
|
||
$responseData = $response->getBody()->getContents();
|
||
$responseArray = json_decode($responseData, true);
|
||
if (empty($responseArray['data']['user']['uid'])) {
|
||
self::setError('用户不存在,请联系管理员开通供销系统账户');
|
||
return false;
|
||
} else {
|
||
$user_id = $responseArray['data']['user']['uid'];
|
||
$find = Db::name('user_other')->where('other_user_id', $user_id)->where('type', 'shop_user')->find();
|
||
if ($find) {
|
||
$user = User::where('id', $find['user_id'])->findOrEmpty();
|
||
if ($user->isEmpty()) {
|
||
self::setError('用户不存在,请联系管理员开通供销系统账户');
|
||
return false;
|
||
}
|
||
$terminal=3;
|
||
$Android=IndexLogic::isAndroid();
|
||
if($Android){
|
||
$terminal=5;
|
||
}
|
||
$ios=IndexLogic::isIOS();
|
||
if($ios){
|
||
$terminal=6;
|
||
}
|
||
$userInfo = UserTokenService::setToken($user->id, $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'],
|
||
];
|
||
} else {
|
||
self::setError('用户不存在,请联系管理员开通供销系统账户');
|
||
return false;
|
||
}
|
||
}
|
||
} catch (GuzzleException $e) {
|
||
//return $this->fail($e->getMessage());self::setError('用户不存在,请联系管理员开通供销系统账户');
|
||
return false;
|
||
}
|
||
}
|
||
//更新登录信息
|
||
$user->login_time = time();
|
||
$user->login_ip = request()->ip();
|
||
$user->save();
|
||
$terminal=3;
|
||
$Android=IndexLogic::isAndroid();
|
||
if($Android){
|
||
$terminal=5;
|
||
}
|
||
$ios=IndexLogic::isIOS();
|
||
if($ios){
|
||
$terminal=6;
|
||
}
|
||
//设置token
|
||
$userInfo = UserTokenService::setToken($user->id, $terminal);
|
||
//返回登录信息
|
||
$avatar = $user->avatar ?: Config::get('project.default_image.user_avatar');
|
||
$avatar = FileService::getFileUrl($avatar);
|
||
$user_id = $jwtData['uid'];
|
||
return [
|
||
'nickname' => $userInfo['nickname'],
|
||
'sn' => $userInfo['sn'],
|
||
'mobile' => $userInfo['mobile'],
|
||
'avatar' => $avatar,
|
||
'token' => $userInfo['token'],
|
||
];
|
||
} catch(\Firebase\JWT\SignatureInvalidException $e) {
|
||
self::setError('签名错误');
|
||
return false;
|
||
} catch(\Firebase\JWT\BeforeValidException $e) {
|
||
self::setError('token无效');
|
||
return false;
|
||
} catch(\Firebase\JWT\ExpiredException $e) {
|
||
self::setError('token已过期');
|
||
return false;
|
||
} catch(\Exception $e) {
|
||
self::setError('非法请求');
|
||
return false;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* @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
|
||
]);
|
||
}
|
||
}
|