Files
huangjingfen/pro_v3.5.1/app/services/store/LoginServices.php
panchengyong c1e74d8e68 chore(php): 统一 ScottPan 文件头与注释域名替换
- 按 docs/renew-code-comment.md 将 PHP 文件头改为带边框的 Author 注释\n- 注释中的 crmeb.com 替换为 uj345.cn(代码字符串中的外链未改)\n- 新增 docs/renew-code-comment.md 说明

Made-with: Cursor
2026-03-29 11:22:58 +08:00

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);
}
}
}