hyperf-jwt登录限制登录次数
composer require firebase/php-jwt:*
登录验证类
<?php
declare(strict_types=1);
namespace App\Logic\Admin;
use App\Annotation\LoginAnnotation;
use App\Constants\Constants;
use App\Exception\EmptyException;
use App\Exception\InvalidConfigException;
use App\Exception\LoginException;
use App\Exception\StatusException;
use App\Exception\UserNotFoundException;
use App\Facade\Redis;
use App\Service\AuthService;
use App\Service\UserService;
use App\Util\Payload;
use App\Util\Prefix;
use App\Util\Token;
class LoginLogic
{
/**
* @LoginAnnotation()
* 登录redis限制错误次数
* @throws EmptyException
* @throws InvalidConfigException
* @throws UserNotFoundException
*
* @return array
*/
public function login(string $username, string $password): array
{
$userLogic = di(UserLogic::class);
$user = di(UserService::class)->getUserByName($username);
if (empty($user)) {
throw new UserNotFoundException('账号不存在!', 1);
}
if ((int) $user->status === 0) {
throw new StatusException('账号已被禁用,请联系管理员!', 1);
}
$max_count = 5;//可重试次数
// $redis = Redis::getInstance();
$redis = Redis::instance();
$key = Prefix::getLoginErrCount($username);
// var_dump(\App\Facade\Redis::get($key)); //直接使用静态方法调用也是可以的。
$login_err_count = $redis->get($key);
if ($login_err_count === false) {
$login_err_count = 0;
$redis->set($key, $login_err_count, 3600);
}
if ($login_err_count >= $max_count) {
throw new LoginException('尝试次数达到上限,锁定一小时内禁止登录!', 1);
}
//判断连续输错次数 可重试5次
if (! $userLogic->verifyPassword($password, $user->password)) {
//错误次数+1
$redis->incr($key);
$login_err_count++;
$diff = $max_count - $login_err_count;
if ($diff) {
$error = "账号或密码错误,还有{$diff}次尝试机会!";
} else {
$error = '尝试次数达到上限,锁定一小时内禁止登录!';
}
throw new LoginException($error, 1);
}
//清除错误次数
$redis->del($key);
//查询角色名称
$authService = di(AuthService::class);
$auth = $authService->info($user->role_id);
if (! $auth) {
throw new EmptyException('当前用户角色不存在,请联系管理员!');
}
if ((int) $auth->status !== Constants::STATUS_ACTIVE) {
throw new StatusException('当前用户角色被禁用,请联系管理员!');
}
$app_name = config('app_name', '');
$app_key = config('app_key', '');
if (empty($app_key) || empty($app_name)) {
throw new InvalidConfigException('配置有误!', 1);
}
$cur_time = time();
$payload = new Payload();
$payload['jti'] = uuid(16);
$payload['iss'] = $app_name;
$payload['sub'] = 'api.onetech.site';
$payload['aud'] = 'api.onetech.site';
$payload['ita'] = $cur_time;
$payload['nbf'] = $cur_time;
$payload['exp'] = $cur_time + 3600 * 24 * 10;
$payload['scopes'] = Constants::SCOPE_ROLE;
$payload['data'] = [
'user_id' => $user->id,
'user_name' => $user->username,
'role_id' => $user->role_id,
'role_name' => $auth->title,
];
$accessToken = Token::instance();
$token = $accessToken->createToken($payload);
$payload['exp'] = $cur_time + 84300;
$payload['scopes'] = Constants::SCOPE_REFRESH;
$refresh_token = $accessToken->createToken($payload);
return compact('token', 'refresh_token');
}
/**
* @param $refresh
* 刷新token
* @throws \Exception
*
* @return array
*/
public function refreshToken($refresh): array
{
$accessToken = Token::instance();
$jwt = $accessToken->checkRefreshToken($refresh);
$data = (array) ($jwt['data']);
$app_name = config('app_name', '');
$cur_time = time();
$payload = new Payload();
$payload['jti'] = uuid(16);
$payload['iss'] = $app_name;
$payload['sub'] = 'api.onetech.site';
$payload['aud'] = 'api.onetech.site';
$payload['ita'] = $cur_time;
$payload['nbf'] = $cur_time;
$payload['exp'] = $cur_time + 3600;
$payload['scopes'] = Constants::SCOPE_ROLE;
$payload['data'] = $data;
$token = $accessToken->createToken($payload);
$payload['exp'] = $cur_time + 84300;
$payload['scopes'] = Constants::SCOPE_REFRESH;
$refresh_token = $accessToken->createToken($payload);
return compact('token', 'refresh_token');
}
}
JWT类
<?php
declare(strict_types=1);
namespace App\Util;
use App\Constants\Constants;
use App\Exception\LoginException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Hyperf\Utils\Traits\StaticInstance;
use InvalidArgumentException;
class Token
{
use StaticInstance;
private static $alg = 'HS256';
private static $app_key;
private $user;
private $user_id;
public function __construct()
{
self::$app_key = config('app_key');
}
public function encode(array $payload): string
{
return JWT::encode($payload, self::$app_key, self::$alg);
}
/**
* @return array
*
* @throws \Exception
*/
public function decode(string $jwt): array
{
try {
$decode = JWT::decode($jwt, self::$app_key, [self::$alg]);
$user = $decode->data;
$this->user = $user;
$this->user_id = $user->user_id;
return (array) $decode;
} catch (ExpiredException $exception) {
//过期token
throw new LoginException('token过期!', -1);
} catch (InvalidArgumentException $exception) {
//参数错误
throw new LoginException('token参数非法!', -1);
} catch (\UnexpectedValueException $exception) {
//token无效
throw new LoginException('token无效!', -1);
}
}
/**
* 创建token
*/
public function createToken(Payload $payload): string
{
return $this->encode($payload->toArray());
}
/**
* @throws \Exception
*/
public function checkToken(string $token): Payload
{
if (empty($token)) {
throw new LoginException('token不能为空!', -1);
}
$decode = $this->decode($token);
if ($decode === null) {
throw new LoginException('token无效!', -1);
}
$jwt = new Payload($decode);
if ($jwt->scopes !== Constants::SCOPE_ROLE) {
throw new LoginException('token参数非法!', -2);
}
return $jwt;
}
/**
* @return array
*
* @throws \Exception
*/
public function checkRefreshToken(string $refresh): array
{
if (empty($refresh)) {
throw new LoginException('token不能为空!', -1);
}
$decode = $this->decode($refresh);
if ($decode === null) {
throw new LoginException('token无效!', -1);
}
$jwt = new Payload($decode);
if ($jwt->scopes !== Constants::SCOPE_REFRESH) {
throw new LoginException('refresh-token参数非法!', -2);
}
return $jwt->toArray();
}
/**
* 刷新token
*
* @param $refresh
*
* @throws \Exception
*/
public function refreshToken($refresh): string
{
if (empty($refresh)) {
throw new LoginException('参数有误!');
}
$jwt = $this->decode($refresh);
if ($jwt === null) {
throw new LoginException('refresh-token参数有误!', -2);
}
if ($jwt['scopes'] !== Constants::SCOPE_REFRESH) {
throw new LoginException('refresh-token参数非法!', -2);
}
return $jwt['data'];
}
public function getUserId(): int
{
return $this->user_id;
}
public function getUser(): object
{
return $this->user;
}
}
已有 0 条评论