This commit is contained in:
wushumin
2026-05-11 15:28:27 +08:00
commit edd1a02157
302 changed files with 67193 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
<?php
namespace app\support;
use Webman\Http\Request;
use support\think\Db;
class AdminAuthService
{
public function __construct()
{
$this->ensureTokenTable();
(new AdminAccessService())->bootstrapDefaults();
}
public function login(string $mobile, string $password, Request $request): array
{
$admin = Db::name('admin_users')->where('mobile', $mobile)->find();
if (!$admin || ($admin['status'] ?? 'enabled') !== 'enabled') {
throw new \RuntimeException('账号不存在或已停用');
}
if (!password_verify($password, (string)$admin['password'])) {
throw new \RuntimeException('手机号或密码错误');
}
$token = bin2hex(random_bytes(24));
$tokenHash = hash('sha256', $token);
$now = date('Y-m-d H:i:s');
$expireTime = date('Y-m-d H:i:s', time() + 7 * 24 * 3600);
// Allow concurrent logins across devices/browsers. Only clean up this user's expired tokens.
Db::name('admin_api_tokens')
->where('admin_user_id', $admin['id'])
->where('expire_time', '<', $now)
->delete();
Db::name('admin_api_tokens')->insert([
'admin_user_id' => (int)$admin['id'],
'token_hash' => $tokenHash,
'expire_time' => $expireTime,
'last_active_at' => $now,
'last_ip' => $request->getRealIp(),
'user_agent' => substr((string)$request->header('user-agent', ''), 0, 500),
'created_at' => $now,
'updated_at' => $now,
]);
Db::name('admin_users')->where('id', $admin['id'])->update([
'last_login_at' => $now,
'updated_at' => $now,
]);
return [
'token' => $token,
'admin_info' => $this->adminInfo((int)$admin['id']),
];
}
public function logout(Request $request): void
{
$token = $this->extractToken($request);
if ($token === '') {
return;
}
Db::name('admin_api_tokens')->where('token_hash', hash('sha256', $token))->delete();
}
public function current(Request $request): ?array
{
$token = $this->extractToken($request);
if ($token === '') {
return null;
}
$record = Db::name('admin_api_tokens')
->where('token_hash', hash('sha256', $token))
->find();
if (!$record) {
return null;
}
if (!empty($record['expire_time']) && strtotime((string)$record['expire_time']) < time()) {
Db::name('admin_api_tokens')->where('id', $record['id'])->delete();
return null;
}
$admin = Db::name('admin_users')->where('id', $record['admin_user_id'])->find();
if (!$admin || ($admin['status'] ?? 'enabled') !== 'enabled') {
return null;
}
Db::name('admin_api_tokens')->where('id', $record['id'])->update([
'last_active_at' => date('Y-m-d H:i:s'),
'last_ip' => $request->getRealIp(),
'user_agent' => substr((string)$request->header('user-agent', ''), 0, 500),
'updated_at' => date('Y-m-d H:i:s'),
]);
return $this->adminInfo((int)$admin['id']);
}
public function hasPermission(array $adminInfo, string $permissionCode): bool
{
if ($permissionCode === '') {
return true;
}
return in_array($permissionCode, $adminInfo['permission_codes'], true);
}
private function adminInfo(int $adminUserId): array
{
$admin = Db::name('admin_users')->where('id', $adminUserId)->find();
$roleIds = Db::name('admin_role_relations')->where('admin_user_id', $adminUserId)->column('role_id');
$roles = $roleIds ? Db::name('admin_roles')->whereIn('id', $roleIds)->select()->toArray() : [];
$permissionIds = $roleIds ? Db::name('admin_role_permissions')->whereIn('role_id', $roleIds)->column('permission_id') : [];
$permissions = $permissionIds ? Db::name('admin_permissions')->whereIn('id', $permissionIds)->select()->toArray() : [];
return [
'id' => (int)($admin['id'] ?? 0),
'name' => $admin['name'] ?? '',
'mobile' => $admin['mobile'] ?? '',
'email' => $admin['email'] ?? '',
'status' => $admin['status'] ?? 'enabled',
'role_names' => array_values(array_map(fn (array $item) => $item['name'], $roles)),
'permission_codes' => array_values(array_unique(array_map(fn (array $item) => $item['code'], $permissions))),
];
}
private function extractToken(Request $request): string
{
$authorization = trim((string)$request->header('authorization', ''));
if (preg_match('/^Bearer\s+(.+)$/i', $authorization, $matches)) {
return trim($matches[1]);
}
return '';
}
private function ensureTokenTable(): void
{
Db::execute(<<<'SQL'
CREATE TABLE IF NOT EXISTS admin_api_tokens (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
admin_user_id BIGINT UNSIGNED NOT NULL,
token_hash VARCHAR(64) NOT NULL,
expire_time DATETIME NOT NULL,
last_active_at DATETIME NULL DEFAULT NULL,
last_ip VARCHAR(64) NOT NULL DEFAULT '',
user_agent VARCHAR(500) NOT NULL DEFAULT '',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_admin_api_tokens_token_hash (token_hash),
KEY idx_admin_api_tokens_admin_user_id (admin_user_id),
KEY idx_admin_api_tokens_expire_time (expire_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='后台登录Token';
SQL);
}
}