- 按 docs/renew-code-comment.md 将 PHP 文件头改为带边框的 Author 注释\n- 注释中的 crmeb.com 替换为 uj345.cn(代码字符串中的外链未改)\n- 新增 docs/renew-code-comment.md 说明 Made-with: Cursor
224 lines
8.1 KiB
PHP
224 lines
8.1 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | Author: ScottPan Team
|
|
// +----------------------------------------------------------------------
|
|
|
|
declare (strict_types=1);
|
|
|
|
namespace app\services\store;
|
|
|
|
use app\Request;
|
|
use app\services\BaseServices;
|
|
use app\dao\store\SystemStoreStaffDao;
|
|
use app\services\system\SystemMenusServices;
|
|
use app\services\system\SystemRoleServices;
|
|
use crmeb\exceptions\AdminException;
|
|
use crmeb\exceptions\AuthException;
|
|
use crmeb\services\CacheService;
|
|
use crmeb\utils\ApiErrorCode;
|
|
use crmeb\utils\JwtAuth;
|
|
use Firebase\JWT\ExpiredException;
|
|
use think\annotation\Inject;
|
|
use think\exception\ValidateException;
|
|
|
|
|
|
/**
|
|
*
|
|
* Class LoginServices
|
|
* @package app\services\user
|
|
* @mixin SystemStoreStaffDao
|
|
*/
|
|
class LoginServices extends BaseServices
|
|
{
|
|
/**
|
|
* 当前门店权限缓存前缀
|
|
*/
|
|
const STORE_RULES_LEVEL = 'store_rules_level_';
|
|
|
|
/**
|
|
* @var SystemStoreStaffDao
|
|
*/
|
|
#[Inject]
|
|
protected SystemStoreStaffDao $dao;
|
|
|
|
/**
|
|
* 获取登陆前的login等信息
|
|
* @return array
|
|
*/
|
|
public function getLoginInfo()
|
|
{
|
|
return [
|
|
'slide' => sys_data('admin_login_slide') ?? [],
|
|
'logo_square' => sys_config('site_logo_square'),//透明
|
|
'logo_rectangle' => sys_config('site_logo'),//方形
|
|
'login_logo' => sys_config('start_login_logo'),//登陆
|
|
'site_name' => sys_config('site_name'),
|
|
'site_url' => sys_config('site_url'),
|
|
'upload_file_size_max' => config('upload.filesize'),//文件上传大小kb
|
|
];
|
|
}
|
|
|
|
/**
|
|
* H5账号登陆
|
|
* @param Request $request
|
|
* @return mixed
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
* @throws \think\exception\DbException
|
|
*/
|
|
public function login($account, $password, $type)
|
|
{
|
|
$storeStaffInfo = $this->dao->getOne(['account' => $account, 'is_del' => 0]);
|
|
|
|
if (!$storeStaffInfo) {
|
|
throw new AdminException('账号不存在!');
|
|
}
|
|
if ($password) {//平台还可以登录
|
|
if (!$storeStaffInfo->status) {
|
|
throw new AdminException('您已被禁止登录!');
|
|
}
|
|
if (!password_verify($password, $storeStaffInfo->pwd)) {
|
|
throw new AdminException('账号或密码错误,请重新输入');
|
|
}
|
|
}
|
|
$storeStaffInfo->last_time = time();
|
|
$storeStaffInfo->last_ip = app('request')->ip();
|
|
$storeStaffInfo->login_count++;
|
|
$storeStaffInfo->save();
|
|
|
|
$tokenInfo = $this->createToken($storeStaffInfo->id, $type, $storeStaffInfo->pwd);
|
|
/** @var SystemMenusServices $services */
|
|
$services = app()->make(SystemMenusServices::class);
|
|
[$menus, $uniqueAuth] = $services->getMenusList($storeStaffInfo->roles, (int)$storeStaffInfo['level'], 2);
|
|
/** @var SystemStoreServices $storeServices */
|
|
$storeServices = app()->make(SystemStoreServices::class);
|
|
$store = $storeServices->get((int)$storeStaffInfo['store_id'], ['id', 'image']);
|
|
return [
|
|
'token' => $tokenInfo['token'],
|
|
'expires_time' => $tokenInfo['params']['exp'],
|
|
'menus' => $menus,
|
|
'unique_auth' => $uniqueAuth,
|
|
'user_info' => [
|
|
'id' => $storeStaffInfo->getData('id'),
|
|
'account' => $storeStaffInfo->getData('account'),
|
|
'avatar' => $storeStaffInfo->getData('avatar'),
|
|
],
|
|
'logo' => $store && isset($store['image']) && $store['image'] ? $store['image'] : sys_config('site_logo'),
|
|
'logo_square' => $store && isset($store['image']) && $store['image'] ? $store['image'] : sys_config('site_logo_square'),
|
|
'version' => get_crmeb_version(),
|
|
'newOrderAudioLink' => get_file_link(sys_config('new_order_audio_link', ''))
|
|
];
|
|
}
|
|
|
|
|
|
/**
|
|
* 重置密码
|
|
* @param $account
|
|
* @param $password
|
|
*/
|
|
public function reset($account, $password)
|
|
{
|
|
$user = $this->dao->getOne(['account|phone' => $account]);
|
|
if (!$user) {
|
|
throw new ValidateException('用户不存在');
|
|
}
|
|
if (!$this->dao->update($user['uid'], ['pwd' => md5((string)$password)], 'uid')) {
|
|
throw new ValidateException('修改密码失败');
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取Admin授权信息
|
|
* @param string $token
|
|
* @return array
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
*/
|
|
public function parseToken(string $token): array
|
|
{
|
|
/** @var CacheService $cacheService */
|
|
$cacheService = app()->make(CacheService::class);
|
|
|
|
if (!$token || $token === 'undefined') {
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN);
|
|
}
|
|
//检测token是否过期
|
|
$md5Token = md5($token);
|
|
if (!$cacheService->hasToken($md5Token) || !($cacheToken = $cacheService->getTokenBucket($md5Token))) {
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN);
|
|
}
|
|
//是否超出有效次数
|
|
if (isset($cacheToken['invalidNum']) && $cacheToken['invalidNum'] >= 3) {
|
|
if (!request()->isCli()) {
|
|
$cacheService->clearToken($md5Token);
|
|
}
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
|
|
}
|
|
|
|
/** @var JwtAuth $jwtAuth */
|
|
$jwtAuth = app()->make(JwtAuth::class);
|
|
//设置解析token
|
|
[$id, $type, $auth] = $jwtAuth->parseToken($token);
|
|
//验证token
|
|
try {
|
|
$jwtAuth->verifyToken();
|
|
$cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
|
|
} catch (ExpiredException $e) {
|
|
$cacheToken['invalidNum'] = isset($cacheToken['invalidNum']) ? $cacheToken['invalidNum']++ : 1;
|
|
$cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
|
|
} catch (\Throwable $e) {
|
|
if (!request()->isCli()) {
|
|
$cacheService->clearToken($md5Token);
|
|
}
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
|
|
}
|
|
//获取管理员信息
|
|
$storeStaffInfo = $this->dao->get($id);
|
|
if (!$storeStaffInfo || !$storeStaffInfo->id || $storeStaffInfo->is_del) {
|
|
if (!request()->isCli()) {
|
|
$cacheService->clearToken($md5Token);
|
|
}
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN_STATUS);
|
|
}
|
|
if ($auth !== md5($storeStaffInfo->pwd)) {
|
|
throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
|
|
}
|
|
|
|
$storeStaffInfo->type = $type;
|
|
return $storeStaffInfo->hidden(['pwd', 'is_del', 'status'])->toArray();
|
|
}
|
|
|
|
/**
|
|
* 后台验证权限
|
|
* @param Request $request
|
|
*/
|
|
public function verifiAuth(Request $request)
|
|
{
|
|
$rule = str_replace('storeapi/', '', trim(strtolower($request->rule()->getRule())));
|
|
if (in_array($rule, ['store/logout', 'menuslist'])) {
|
|
return true;
|
|
}
|
|
$method = trim(strtolower($request->method()));
|
|
/** @var SystemRoleServices $roleServices */
|
|
$roleServices = app()->make(SystemRoleServices::class);
|
|
$auth = $roleServices->getAllRoles(2, 2, self::STORE_RULES_LEVEL);
|
|
//验证访问接口是否存在
|
|
if ($auth && !in_array($method . '@@' . $rule, array_map(function ($item) {
|
|
return trim(strtolower($item['methods'])) . '@@' . trim(strtolower(str_replace(' ', '', $item['api_url'])));
|
|
}, $auth))) {
|
|
return true;
|
|
}
|
|
$auth = $roleServices->getRolesByAuth($request->storeStaffInfo()['roles'], 2, 2, self::STORE_RULES_LEVEL);
|
|
//验证访问接口是否有权限
|
|
if ($auth && empty(array_filter($auth, function ($item) use ($rule, $method) {
|
|
if (trim(strtolower($item['api_url'])) === $rule && $method === trim(strtolower($item['methods'])))
|
|
return true;
|
|
}))) {
|
|
throw new AuthException(ApiErrorCode::ERR_AUTH);
|
|
}
|
|
}
|
|
|
|
|
|
}
|