项目初始化

This commit is contained in:
2026-03-18 15:54:43 +08:00
commit dfcd762e23
601 changed files with 57883 additions and 0 deletions

369
app/admin/library/Auth.php Normal file
View File

@@ -0,0 +1,369 @@
<?php
declare(strict_types=1);
namespace app\admin\library;
use Throwable;
use ba\Random;
use support\think\Db;
use app\admin\model\Admin;
use app\common\facade\Token;
use app\admin\model\AdminGroup;
/**
* 管理员权限类Webman 迁移版)
* @property int $id 管理员ID
* @property string $username 管理员用户名
* @property string $nickname 管理员昵称
* @property string $email 管理员邮箱
* @property string $mobile 管理员手机号
*/
class Auth extends \ba\Auth
{
public const LOGIN_RESPONSE_CODE = 303;
public const NEED_LOGIN = 'need login';
public const LOGGED_IN = 'logged in';
public const TOKEN_TYPE = 'admin';
protected bool $loginEd = false;
protected string $error = '';
protected ?Admin $model = null;
protected string $token = '';
protected string $refreshToken = '';
protected int $keepTime = 86400;
protected int $refreshTokenKeepTime = 2592000;
protected array $allowFields = ['id', 'username', 'nickname', 'avatar', 'last_login_time'];
public function __construct(array $config = [])
{
parent::__construct($config);
$this->setKeepTime((int) config('buildadmin.admin_token_keep_time', 86400 * 3));
}
public function __get($name): mixed
{
return $this->model?->$name;
}
/**
* 初始化Webman从 request 获取或创建新实例)
*/
public static function instance(array $options = []): Auth
{
$request = function_exists('request') ? request() : null;
if ($request !== null && isset($request->adminAuth) && $request->adminAuth instanceof Auth) {
return $request->adminAuth;
}
$auth = new static($options);
if ($request !== null) {
$request->adminAuth = $auth;
}
return $auth;
}
public function init(string $token): bool
{
$tokenData = Token::get($token);
if ($tokenData) {
Token::tokenExpirationCheck($tokenData);
$userId = (int) $tokenData['user_id'];
if ($tokenData['type'] === self::TOKEN_TYPE && $userId > 0) {
$this->model = Admin::where('id', $userId)->find();
if (!$this->model) {
$this->setError('Account not exist');
return false;
}
if ($this->model['status'] !== 'enable') {
$this->setError('Account disabled');
return false;
}
$this->token = $token;
$this->loginSuccessful();
return true;
}
}
$this->setError('Token login failed');
$this->reset();
return false;
}
public function login(string $username, string $password, bool $keep = false): bool
{
$this->model = Admin::where('username', $username)->find();
if (!$this->model) {
$this->setError('Username is incorrect');
return false;
}
if ($this->model->status === 'disable') {
$this->setError('Account disabled');
return false;
}
$adminLoginRetry = config('buildadmin.admin_login_retry');
if ($adminLoginRetry) {
$lastLoginTime = $this->model->getData('last_login_time');
if ($lastLoginTime) {
if ($this->model->login_failure > 0 && time() - $lastLoginTime >= 86400) {
$this->model->login_failure = 0;
$this->model->save();
$this->model = Admin::where('username', $username)->find();
}
if ($this->model->login_failure >= $adminLoginRetry) {
$this->setError('Please try again after 1 day');
return false;
}
}
}
if (!verify_password($password, $this->model->password, ['salt' => $this->model->salt ?? ''])) {
$this->loginFailed();
$this->setError('Password is incorrect');
return false;
}
if (config('buildadmin.admin_sso')) {
Token::clear(self::TOKEN_TYPE, $this->model->id);
Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id);
}
if ($keep) {
$this->setRefreshToken($this->refreshTokenKeepTime);
}
if (!$this->loginSuccessful()) {
return false;
}
return true;
}
public function setRefreshToken(int $keepTime = 0): void
{
$this->refreshToken = Random::uuid();
Token::set($this->refreshToken, self::TOKEN_TYPE . '-refresh', $this->model->id, $keepTime);
}
public function loginSuccessful(): bool
{
if (!$this->model) {
return false;
}
$this->model->startTrans();
try {
$this->model->login_failure = 0;
$this->model->last_login_time = time();
$this->model->last_login_ip = function_exists('request') && request() ? request()->getRealIp() : '';
$this->model->save();
$this->loginEd = true;
if (!$this->token) {
$this->token = Random::uuid();
Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime);
}
$this->model->commit();
} catch (Throwable $e) {
$this->model->rollback();
$this->setError($e->getMessage());
return false;
}
return true;
}
public function loginFailed(): bool
{
if (!$this->model) {
return false;
}
$this->model->startTrans();
try {
$this->model->login_failure++;
$this->model->last_login_time = time();
$this->model->last_login_ip = function_exists('request') && request() ? request()->getRealIp() : '';
$this->model->save();
$this->model->commit();
} catch (Throwable $e) {
$this->model->rollback();
}
return $this->reset();
}
public function logout(): bool
{
if (!$this->loginEd) {
$this->setError('You are not logged in');
return false;
}
return $this->reset();
}
public function isLogin(): bool
{
return $this->loginEd;
}
public function getAdmin(): Admin
{
return $this->model;
}
public function getToken(): string
{
return $this->token;
}
public function getRefreshToken(): string
{
return $this->refreshToken;
}
public function getInfo(): array
{
if (!$this->model) {
return [];
}
$info = $this->model->toArray();
$info = array_intersect_key($info, array_flip($this->getAllowFields()));
// 与 ThinkPHP 一致token 为主认证令牌refresh_token 仅 keep=true 时有值
$token = $this->token;
if (!$token && $this->loginEd) {
$token = Random::uuid();
Token::set($token, self::TOKEN_TYPE, $this->model->id, $this->keepTime);
$this->token = $token;
}
$info['token'] = $token ?: '';
$info['refresh_token'] = $this->refreshToken ?: '';
// last_login_time 与 ThinkPHP 一致返回整数时间戳
if (isset($info['last_login_time'])) {
$info['last_login_time'] = (int) $info['last_login_time'];
}
return $info;
}
public function getAllowFields(): array
{
return $this->allowFields;
}
public function setAllowFields($fields): void
{
$this->allowFields = $fields;
}
public function setKeepTime(int $keepTime = 0): void
{
$this->keepTime = $keepTime;
}
public function check(string $name, int $uid = 0, string $relation = 'or', string $mode = 'url'): bool
{
return parent::check($name, $uid ?: $this->id, $relation, $mode);
}
public function getGroups(int $uid = 0): array
{
return parent::getGroups($uid ?: $this->id);
}
public function getRuleList(int $uid = 0): array
{
return parent::getRuleList($uid ?: $this->id);
}
public function getRuleIds(int $uid = 0): array
{
return parent::getRuleIds($uid ?: $this->id);
}
public function getMenus(int $uid = 0): array
{
return parent::getMenus($uid ?: $this->id);
}
public function isSuperAdmin(): bool
{
return in_array('*', $this->getRuleIds());
}
public function getAdminChildGroups(): array
{
$groupIds = Db::name('admin_group_access')
->where('uid', $this->id)
->select();
$children = [];
foreach ($groupIds as $group) {
$this->getGroupChildGroups($group['group_id'], $children);
}
return array_unique($children);
}
public function getGroupChildGroups(int $groupId, array &$children): void
{
$childrenTemp = AdminGroup::where('pid', $groupId)
->where('status', 1)
->select();
foreach ($childrenTemp as $item) {
$children[] = $item['id'];
$this->getGroupChildGroups($item['id'], $children);
}
}
public function getGroupAdmins(array $groups): array
{
return Db::name('admin_group_access')
->where('group_id', 'in', $groups)
->column('uid');
}
public function getAllAuthGroups(string $dataLimit, array $groupQueryWhere = [['status', '=', 1]]): array
{
$rules = $this->getRuleIds();
$allAuthGroups = [];
$groups = AdminGroup::where($groupQueryWhere)->select();
foreach ($groups as $group) {
if ($group['rules'] === '*') {
continue;
}
$groupRules = explode(',', $group['rules']);
$all = true;
foreach ($groupRules as $groupRule) {
if (!in_array($groupRule, $rules)) {
$all = false;
break;
}
}
if ($all) {
if ($dataLimit === 'allAuth' || ($dataLimit === 'allAuthAndOthers' && array_diff($rules, $groupRules))) {
$allAuthGroups[] = $group['id'];
}
}
}
return $allAuthGroups;
}
public function setError($error): Auth
{
$this->error = $error;
return $this;
}
public function getError(): string
{
return $this->error ? __($this->error) : '';
}
protected function reset(bool $deleteToken = true): bool
{
if ($deleteToken && $this->token) {
Token::delete($this->token);
}
$this->token = '';
$this->loginEd = false;
$this->model = null;
$this->refreshToken = '';
$this->setError('');
$this->setKeepTime((int) config('buildadmin.admin_token_keep_time', 86400 * 3));
return true;
}
}