系统认证接口
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\traits\ResponseTrait;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use app\common\utils\SystemAuth;
|
||||
use app\common\utils\Jwt;
|
||||
use app\common\model\User;
|
||||
use app\common\model\Systems;
|
||||
use support\Redis;
|
||||
|
||||
class SystemController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected $noNeedLogin = ['auth'];
|
||||
|
||||
protected $noNeedHeaderData = ['auth'];
|
||||
/**
|
||||
* 系统间认证接口
|
||||
* POST /api/system/auth
|
||||
*/
|
||||
public function auth(Request $request): Response
|
||||
{
|
||||
$userId = $request->post('user_id');
|
||||
$timestamp = (int)$request->post('timestamp');
|
||||
$signature = $request->post('signature');
|
||||
$systemCode = $request->post('system_code');
|
||||
|
||||
// 参数验证
|
||||
if (empty($userId) || empty($timestamp) || empty($signature)) {
|
||||
return $this->error('参数不完整', 400);
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
$secret = config('system_auth.shared_secret');
|
||||
$expire = config('system_auth.signature_expire', 600);
|
||||
|
||||
// 验证时间戳(10分钟有效期)
|
||||
if (!SystemAuth::verifyTimestamp($timestamp, $expire)) {
|
||||
return $this->error('请求已过期', 401);
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
if (!SystemAuth::verifySignature($userId, $timestamp, $signature, $secret)) {
|
||||
return $this->error('签名验证失败', 401);
|
||||
}
|
||||
|
||||
// 查找用户
|
||||
$user = User::find($userId);
|
||||
if (!$user) {
|
||||
return $this->error('用户不存在', 404);
|
||||
}
|
||||
|
||||
// 验证系统(如果提供了 system_code)
|
||||
$system = null;
|
||||
if ($systemCode) {
|
||||
$system = Systems::where('code', $systemCode)->first();
|
||||
if (!$system) {
|
||||
return $this->error('系统不存在', 404);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 corp_abbr(优先从请求参数获取,否则通过用户 corp_id 查询)
|
||||
$corpAbbr = $request->post('corp_abbr');
|
||||
if (!$corpAbbr && $user->corp_id) {
|
||||
$corp = \app\common\model\Corp::find($user->corp_id);
|
||||
$corpAbbr = $corp ? $corp->abbr : '';
|
||||
}
|
||||
|
||||
// 构建 JWT payload
|
||||
$payload = $this->buildJwtPayload($user, $system);
|
||||
|
||||
// 生成 access_token
|
||||
$jwt = new Jwt();
|
||||
$token = $jwt->generateToken($payload);
|
||||
|
||||
// 生成 refresh_token
|
||||
$refreshToken = $this->generateRefreshToken($user->id, $systemCode ?? '');
|
||||
|
||||
// 获取 home_url
|
||||
$homeUrl = $system ? $this->getHome($system->id, $payload) : '';
|
||||
|
||||
// 记录 token 到 Redis 和 MySQL
|
||||
$this->recordUserToken($user->id, $token, $systemCode ?? '');
|
||||
|
||||
// 构建用户信息(去除敏感信息)
|
||||
$userInfo = [
|
||||
'id' => $user->id,
|
||||
'sn' => $user->sn ?? '',
|
||||
'name' => $user->name ?? '',
|
||||
'avatar' => $user->avatar ?? '',
|
||||
'phone' => $user->phone ?? '',
|
||||
'email' => $user->email ?? '',
|
||||
'sex' => $user->sex ?? '',
|
||||
'position' => $user->position ?? '',
|
||||
'status' => $user->status ?? 1,
|
||||
'corp_id' => $user->corp_id,
|
||||
];
|
||||
|
||||
return $this->success([
|
||||
'access_token' => $token,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_in' => config('jwt.jwt_expiration'),
|
||||
'system_code' => $systemCode ?? '',
|
||||
'corp_abbr' => $corpAbbr ?? '',
|
||||
'login_type' => 'system',
|
||||
'home_url' => $homeUrl,
|
||||
'user_info' => $userInfo,
|
||||
], '认证成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 JWT payload
|
||||
*/
|
||||
private function buildJwtPayload(User $user, ?Systems $system): array
|
||||
{
|
||||
$payload = [
|
||||
'user_id' => $user->id,
|
||||
'sn' => $user->sn ?? '',
|
||||
'name' => $user->name ?? '',
|
||||
'iat' => time(),
|
||||
'exp' => time() + config('jwt.jwt_expiration'),
|
||||
];
|
||||
|
||||
if ($system) {
|
||||
$payload['system_code'] = $system->code;
|
||||
$payload['system_id'] = $system->id;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 refresh_token
|
||||
*/
|
||||
private function generateRefreshToken(int $userId, string $systemCode): string
|
||||
{
|
||||
$refreshToken = bin2hex(random_bytes(32));
|
||||
|
||||
// 存储到 Redis
|
||||
$key = "refresh_token:{$refreshToken}";
|
||||
$expire = config('jwt.jwt_refresh_token_expiration');
|
||||
Redis::setex($key, $expire, json_encode([
|
||||
'user_id' => $userId,
|
||||
'system_code' => $systemCode,
|
||||
]));
|
||||
|
||||
return $refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户首页地址
|
||||
*/
|
||||
private function getHome(int $systemId, array $payload): string
|
||||
{
|
||||
// 简单实现,可以根据实际需求调整
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户token到 Redis 和 MySQL
|
||||
*/
|
||||
private function recordUserToken(int $userId, string $token, string $systemCode): void
|
||||
{
|
||||
$request = request();
|
||||
$ip = $request ? $request->getRealIp() : '';
|
||||
$ua = $request ? $request->header('user-agent', '') : '';
|
||||
$now = time();
|
||||
$expireAt = $now + config('jwt.jwt_expiration');
|
||||
|
||||
// Redis Set 用户token集合
|
||||
Redis::sAdd("user_tokens:{$userId}:{$systemCode}", $token);
|
||||
Redis::expire("user_tokens:{$userId}:{$systemCode}", config('jwt.jwt_expiration'));
|
||||
|
||||
// Redis Hash token元信息
|
||||
$meta = [
|
||||
'system_code' => $systemCode,
|
||||
'login_ip' => $ip,
|
||||
'user_agent' => $ua,
|
||||
'login_time' => $now,
|
||||
'expired_at' => $expireAt,
|
||||
];
|
||||
Redis::hMSet("user_token_meta:{$token}", $meta);
|
||||
Redis::expire("user_token_meta:{$token}", config('jwt.jwt_expiration'));
|
||||
|
||||
// MySQL 持久化
|
||||
\app\common\model\UserTokenLog::create([
|
||||
'user_id' => $userId,
|
||||
'token' => $token,
|
||||
'system_code' => $systemCode,
|
||||
'login_ip' => $ip,
|
||||
'user_agent' => $ua,
|
||||
'expired_at' => date('Y-m-d H:i:s', $expireAt),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user