webman后台
This commit is contained in:
352
dafuweng-webman/app/common/library/Auth.php
Normal file
352
dafuweng-webman/app/common/library/Auth.php
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use Throwable;
|
||||
use ba\Random;
|
||||
use support\think\Db;
|
||||
use app\common\model\User;
|
||||
use app\common\facade\Token;
|
||||
use Webman\Http\Request;
|
||||
|
||||
/**
|
||||
* 公共权限类(会员权限类)
|
||||
*/
|
||||
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 = 'user';
|
||||
|
||||
protected bool $loginEd = false;
|
||||
protected string $error = '';
|
||||
protected ?User $model = null;
|
||||
protected string $token = '';
|
||||
protected string $refreshToken = '';
|
||||
protected int $keepTime = 86400;
|
||||
protected int $refreshTokenKeepTime = 2592000;
|
||||
|
||||
protected array $allowFields = ['id', 'username', 'nickname', 'email', 'mobile', 'avatar', 'gender', 'birthday', 'money', 'score', 'join_time', 'motto', 'last_login_time', 'last_login_ip'];
|
||||
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
parent::__construct(array_merge([
|
||||
'auth_group' => 'user_group',
|
||||
'auth_group_access' => '',
|
||||
'auth_rule' => 'user_rule',
|
||||
], $config));
|
||||
|
||||
$this->setKeepTime((int)config('buildadmin.user_token_keep_time', 86400));
|
||||
}
|
||||
|
||||
public function __get($name): mixed
|
||||
{
|
||||
return $this->model?->$name;
|
||||
}
|
||||
|
||||
public static function instance(array $options = []): Auth
|
||||
{
|
||||
$request = function_exists('request') ? request() : null;
|
||||
if ($request && !isset($request->userAuth)) {
|
||||
$request->userAuth = new static($options);
|
||||
}
|
||||
return $request && isset($request->userAuth) ? $request->userAuth : new static($options);
|
||||
}
|
||||
|
||||
public function init($token): bool
|
||||
{
|
||||
$tokenData = Token::get($token);
|
||||
if ($tokenData) {
|
||||
Token::tokenExpirationCheck($tokenData);
|
||||
$userId = $tokenData['user_id'];
|
||||
if ($tokenData['type'] == self::TOKEN_TYPE && $userId > 0) {
|
||||
$this->model = User::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 register(string $username, string $password = '', string $mobile = '', string $email = '', int $group = 1, array $extend = []): bool
|
||||
{
|
||||
$request = function_exists('request') ? request() : null;
|
||||
$ip = $request ? $request->getRealIp() : '0.0.0.0';
|
||||
|
||||
if ($email && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$this->setError(__('Email'));
|
||||
return false;
|
||||
}
|
||||
if ($username && !preg_match('/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/', $username)) {
|
||||
$this->setError(__('Username'));
|
||||
return false;
|
||||
}
|
||||
if (User::where('email', $email)->find() && $email) {
|
||||
$this->setError(__('Email') . ' ' . __('already exists'));
|
||||
return false;
|
||||
}
|
||||
if (User::where('username', $username)->find()) {
|
||||
$this->setError(__('Username') . ' ' . __('already exists'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$nickname = preg_replace_callback('/1[3-9]\d{9}/', fn($m) => substr($m[0], 0, 3) . '****' . substr($m[0], 7), $username);
|
||||
$time = time();
|
||||
$data = [
|
||||
'group_id' => $group,
|
||||
'nickname' => $nickname,
|
||||
'join_ip' => $ip,
|
||||
'join_time' => $time,
|
||||
'last_login_ip' => $ip,
|
||||
'last_login_time' => $time,
|
||||
'status' => 'enable',
|
||||
];
|
||||
$data = array_merge(compact('username', 'password', 'mobile', 'email'), $data, $extend);
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$this->model = User::create($data);
|
||||
$this->token = Random::uuid();
|
||||
Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime);
|
||||
Db::commit();
|
||||
|
||||
if ($password) {
|
||||
$this->model->resetPassword($this->model->id, $password);
|
||||
}
|
||||
|
||||
event_trigger('userRegisterSuccess', $this->model);
|
||||
} catch (Throwable $e) {
|
||||
$this->setError($e->getMessage());
|
||||
Db::rollback();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function login(string $username, string $password, bool $keep): bool
|
||||
{
|
||||
$accountType = false;
|
||||
if (preg_match('/^1[3-9]\d{9}$/', $username)) $accountType = 'mobile';
|
||||
elseif (filter_var($username, FILTER_VALIDATE_EMAIL)) $accountType = 'email';
|
||||
elseif (preg_match('/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/', $username)) $accountType = 'username';
|
||||
if (!$accountType) {
|
||||
$this->setError('Account not exist');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->model = User::where($accountType, $username)->find();
|
||||
if (!$this->model) {
|
||||
$this->setError('Account not exist');
|
||||
return false;
|
||||
}
|
||||
if ($this->model->status == 'disable') {
|
||||
$this->setError('Account disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
$userLoginRetry = config('buildadmin.user_login_retry');
|
||||
if ($userLoginRetry && $this->model->last_login_time) {
|
||||
if ($this->model->login_failure > 0 && time() - strtotime($this->model->last_login_time) >= 86400) {
|
||||
$this->model->login_failure = 0;
|
||||
$this->model->save();
|
||||
$this->model = User::where($accountType, $username)->find();
|
||||
}
|
||||
if ($this->model->login_failure >= $userLoginRetry) {
|
||||
$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.user_sso')) {
|
||||
Token::clear(self::TOKEN_TYPE, $this->model->id);
|
||||
Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id);
|
||||
}
|
||||
|
||||
if ($keep) $this->setRefreshToken($this->refreshTokenKeepTime);
|
||||
$this->loginSuccessful();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function direct(int $userId): bool
|
||||
{
|
||||
$this->model = User::find($userId);
|
||||
if (!$this->model) return false;
|
||||
if (config('buildadmin.user_sso')) {
|
||||
Token::clear(self::TOKEN_TYPE, $this->model->id);
|
||||
Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id);
|
||||
}
|
||||
return $this->loginSuccessful();
|
||||
}
|
||||
|
||||
public function loginSuccessful(): bool
|
||||
{
|
||||
if (!$this->model) return false;
|
||||
$request = function_exists('request') ? request() : null;
|
||||
$ip = $request ? $request->getRealIp() : '0.0.0.0';
|
||||
$this->model->startTrans();
|
||||
try {
|
||||
$this->model->login_failure = 0;
|
||||
$this->model->last_login_time = date('Y-m-d H:i:s');
|
||||
$this->model->last_login_ip = $ip;
|
||||
$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;
|
||||
$request = function_exists('request') ? request() : null;
|
||||
$ip = $request ? $request->getRealIp() : '0.0.0.0';
|
||||
$this->model->startTrans();
|
||||
try {
|
||||
$this->model->login_failure++;
|
||||
$this->model->last_login_time = date('Y-m-d H:i:s');
|
||||
$this->model->last_login_ip = $ip;
|
||||
$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 getUser(): User
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
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 getRefreshToken(): string
|
||||
{
|
||||
return $this->refreshToken;
|
||||
}
|
||||
|
||||
public function getUserInfo(): array
|
||||
{
|
||||
if (!$this->model) return [];
|
||||
$info = $this->model->toArray();
|
||||
$info = array_intersect_key($info, array_flip($this->getAllowFields()));
|
||||
$info['token'] = $this->getToken();
|
||||
$info['refresh_token'] = $this->getRefreshToken();
|
||||
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 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 isSuperUser(): bool
|
||||
{
|
||||
return in_array('*', $this->getRuleIds());
|
||||
}
|
||||
|
||||
public function setError(string $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.user_token_keep_time', 86400));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user