Files
dafuweng-saiadmin6.x/server/app/api/cache/UserCache.php

135 lines
4.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\api\cache;
use support\think\Cache;
/**
* API 用户信息 Redis 缓存
* key = base64(user_id)value = 加密后的用户信息 JSON
*/
class UserCache
{
private static function prefix(): string
{
return config('api.user_cache_prefix', 'api:user:');
}
private static function expire(): int
{
return (int) config('api.user_cache_expire', 604800);
}
private static function encryptKey(): string
{
$key = config('api.user_encrypt_key', 'dafuweng_api_user_cache_key_32');
return str_pad($key, 32, '0', STR_PAD_RIGHT);
}
/** 加密 */
public static function encrypt(string $data): string
{
$key = self::encryptKey();
$iv = substr(md5($key), 0, 16);
return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv));
}
/** 解密 */
public static function decrypt(string $data): string
{
$key = self::encryptKey();
$iv = substr(md5($key), 0, 16);
$dec = openssl_decrypt(base64_decode($data, true), 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
return $dec !== false ? $dec : '';
}
/**
* 写入用户信息到 Redis
* @param int $userId
* @param array $userInfo 从数据库读取的用户信息(可含敏感字段,会加密存储)
*/
public static function setUser(int $userId, array $userInfo): bool
{
$key = self::prefix() . base64_encode((string) $userId);
$value = self::encrypt(json_encode($userInfo));
return Cache::set($key, $value, self::expire());
}
/**
* 从 Redis 读取用户信息
* @return array 解密后的用户信息,不存在或失败返回空数组
*/
public static function getUser(int $userId): array
{
$key = self::prefix() . base64_encode((string) $userId);
$value = Cache::get($key);
if ($value === null || $value === '') {
return [];
}
$dec = self::decrypt($value);
if ($dec === '') {
return [];
}
$data = json_decode($dec, true);
return is_array($data) ? $data : [];
}
/**
* 仅从缓存读取用户平台币 coin不查库低延迟
* @return int|float|null 余额,缓存未命中返回 null缓存中 coin 可能为字符串,统一转为数值)
*/
public static function getUserCoin(int $userId): int|float|null
{
$user = self::getUser($userId);
if (empty($user) || !array_key_exists('coin', $user)) {
return null;
}
$coin = $user['coin'];
if (is_int($coin) || is_float($coin)) {
return $coin;
}
if (is_string($coin) && is_numeric($coin)) {
return str_contains($coin, '.') ? (float) $coin : (int) $coin;
}
return null;
}
/** 删除用户缓存 */
public static function deleteUser(int $userId): bool
{
$key = self::prefix() . base64_encode((string) $userId);
return Cache::delete($key);
}
/** user-token 黑名单前缀(退出登录后使 token 失效) */
private static function blacklistPrefix(): string
{
return config('api.user_cache_prefix', 'api:user:') . 'token_blacklist:';
}
/**
* 将 user-token 加入黑名单(退出登录)
* @param string $token 完整 token 字符串
* @param int $ttl 黑名单过期时间(秒),建议为 token 剩余有效期
*/
public static function addTokenToBlacklist(string $token, int $ttl = 86400): bool
{
if ($ttl <= 0) {
return true;
}
$key = self::blacklistPrefix() . md5($token);
return Cache::set($key, '1', $ttl);
}
/**
* 检查 user-token 是否在黑名单中(已退出)
*/
public static function isTokenBlacklisted(string $token): bool
{
$key = self::blacklistPrefix() . md5($token);
$val = Cache::get($key);
return $val !== null && $val !== '';
}
}