重新登录或注册后清除掉原有用户的user-token保证只有一个用户能够登录
This commit is contained in:
47
server/app/api/cache/UserCache.php
vendored
47
server/app/api/cache/UserCache.php
vendored
@@ -131,4 +131,51 @@ class UserCache
|
|||||||
$val = Cache::get($key);
|
$val = Cache::get($key);
|
||||||
return $val !== null && $val !== '';
|
return $val !== null && $val !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 当前有效 user-token 按用户存储的 key 前缀(重新登录/注册后覆盖,保证单用户单 token) */
|
||||||
|
private static function currentTokenPrefix(): string
|
||||||
|
{
|
||||||
|
return config('api.user_token_current_prefix', 'api:user:current_token:');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function userTokenExpire(): int
|
||||||
|
{
|
||||||
|
return (int) config('api.user_token_exp', 604800);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置该用户当前唯一有效的 user-token(登录/注册时调用,会覆盖该用户之前的 token)
|
||||||
|
* @param int $userId 用户 ID
|
||||||
|
* @param string $token 完整 user-token 字符串
|
||||||
|
*/
|
||||||
|
public static function setCurrentUserToken(int $userId, string $token): bool
|
||||||
|
{
|
||||||
|
if ($userId <= 0 || $token === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$key = self::currentTokenPrefix() . $userId;
|
||||||
|
return Cache::set($key, $token, self::userTokenExpire());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该用户当前在服务端登记的有效 user-token,不存在或已过期返回 null
|
||||||
|
*/
|
||||||
|
public static function getCurrentUserToken(int $userId): ?string
|
||||||
|
{
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$key = self::currentTokenPrefix() . $userId;
|
||||||
|
$value = Cache::get($key);
|
||||||
|
return $value !== null && $value !== '' ? (string) $value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验请求中的 token 是否为该用户当前唯一有效 token
|
||||||
|
*/
|
||||||
|
public static function isCurrentUserToken(int $userId, string $token): bool
|
||||||
|
{
|
||||||
|
$current = self::getCurrentUserToken($userId);
|
||||||
|
return $current !== null && $current === $token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class UserLogic
|
|||||||
UserCache::setUser((int) $user->id, $userArr);
|
UserCache::setUser((int) $user->id, $userArr);
|
||||||
|
|
||||||
$userToken = $this->generateUserToken((int) $user->id);
|
$userToken = $this->generateUserToken((int) $user->id);
|
||||||
|
// 同一用户只保留最新一次登录的 token,旧 token 自动失效
|
||||||
|
UserCache::setCurrentUserToken((int) $user->id, $userToken);
|
||||||
return [
|
return [
|
||||||
'user' => $userArr,
|
'user' => $userArr,
|
||||||
'user-token' => $userToken,
|
'user-token' => $userToken,
|
||||||
@@ -94,6 +96,8 @@ class UserLogic
|
|||||||
UserCache::setUser((int) $user->id, $userArr);
|
UserCache::setUser((int) $user->id, $userArr);
|
||||||
|
|
||||||
$userToken = $this->generateUserToken((int) $user->id);
|
$userToken = $this->generateUserToken((int) $user->id);
|
||||||
|
// 同一用户只保留最新一次登录的 token,旧 token 自动失效
|
||||||
|
UserCache::setCurrentUserToken((int) $user->id, $userToken);
|
||||||
return [
|
return [
|
||||||
'user' => $userArr,
|
'user' => $userArr,
|
||||||
'user-token' => $userToken,
|
'user-token' => $userToken,
|
||||||
@@ -174,7 +178,15 @@ class UserLogic
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$id = $extend['id'] ?? null;
|
$id = $extend['id'] ?? null;
|
||||||
return $id !== null ? (int) $id : null;
|
if ($id === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$userId = (int) $id;
|
||||||
|
// 同一用户只允许当前登记的 token 生效,重新登录/注册后旧 token 失效
|
||||||
|
if (!UserCache::isCurrentUserToken($userId, $userToken)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $userId;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ return [
|
|||||||
'auth_token_device_prefix' => env('API_AUTH_TOKEN_DEVICE_PREFIX', 'api:auth_token:'),
|
'auth_token_device_prefix' => env('API_AUTH_TOKEN_DEVICE_PREFIX', 'api:auth_token:'),
|
||||||
// user-token 有效期(秒),默认 7 天
|
// user-token 有效期(秒),默认 7 天
|
||||||
'user_token_exp' => (int) env('API_USER_TOKEN_EXP', 604800),
|
'user_token_exp' => (int) env('API_USER_TOKEN_EXP', 604800),
|
||||||
|
// 按用户存储当前有效 user-token 的 Redis key 前缀(同一用户仅保留最新一次登录的 token)
|
||||||
|
'user_token_current_prefix' => env('API_USER_TOKEN_CURRENT_PREFIX', 'api:user:current_token:'),
|
||||||
// 用户信息 Redis 缓存过期时间(秒),默认 7 天
|
// 用户信息 Redis 缓存过期时间(秒),默认 7 天
|
||||||
'user_cache_expire' => (int) env('API_USER_CACHE_EXPIRE', 604800),
|
'user_cache_expire' => (int) env('API_USER_CACHE_EXPIRE', 604800),
|
||||||
// 用户缓存 Redis key 前缀
|
// 用户缓存 Redis key 前缀
|
||||||
|
|||||||
Reference in New Issue
Block a user