study-api-v2/app/Http/Controllers/Admin/AuthController.php

320 lines
9.8 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
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BaseController;
use App\Models\User;
use App\Services\Auth\TokenAuthService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\JsonResponse;
/**
* 后台认证控制器 (支持Token认证)
* @package App\Http\Controllers\Admin
*/
class AuthController extends BaseController
{
/**
* Token认证服务
*/
protected TokenAuthService $tokenAuthService;
/**
* 构造函数
*/
public function __construct(TokenAuthService $tokenAuthService)
{
$this->tokenAuthService = $tokenAuthService;
}
/**
* 用户登录 (返回Token)
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function login(Request $request) : JsonResponse
{
// 验证请求数据
$validator = Validator::make($request->all(), [
'username' => ['required', 'string'],
'password' => ['required', 'string'],
'device_name' => ['string', 'nullable'] // 设备名称用于Token标识
], [
'username.required' => '请输入用户名',
'password.required' => '请输入密码',
]);
if ($validator->fails()) {
return $this->Field($validator->errors()->first(), 422);
}
$credentials = $validator->validated();
// 手动验证用户
$user = User::where('username', $credentials['username'])
->where('status', 0) // 0表示正常状态1表示停用
->where('deleted', 0) // 确保用户未被删除
->first();
if (!$user || !Hash::check($credentials['password'], $user->password)) {
return $this->Field('用户名或密码错误,或账户已被停用', 401);
}
// 设备名称默认为APP
$deviceName = $credentials['device_name'] ?? 'APP-' . now()->format('Y-m-d H:i:s');
// 创建Token (删除该设备的旧Token避免重复)
$user->tokens()->where('name', $deviceName)->delete();
$token = $user->createToken($deviceName);
// 更新最后登录信息
$user->update([
'login_ip' => $request->ip(),
'login_date' => now(),
]);
return $this->SuccessObject([
'user' => [
'id' => $user->id,
'username' => $user->username,
'nickname' => $user->nickname,
'email' => $user->email,
'mobile' => $user->mobile,
'avatar' => $user->avatar,
'dept_id' => $user->dept_id,
],
'token' => [
'access_token' => $token->plainTextToken,
'token_type' => 'Bearer',
'expires_in' => null, // Sanctum默认不过期可以在config/sanctum.php配置
],
'message' => '登录成功'
]);
}
/**
* APP登出 (删除当前Token)
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function logout(Request $request) : JsonResponse
{
$user = $request->user();
$currentToken = $request->bearerToken();
// 清空当前token的缓存
if ($currentToken) {
$this->tokenAuthService->clearTokenCache($currentToken);
}
// 删除当前使用的token
$user->currentAccessToken()->delete();
return $this->Success(['message' => '登出成功']);
}
/**
* 登出所有设备 (删除用户所有Token)
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function logoutAll(Request $request) : JsonResponse
{
$user = $request->user();
// 清空用户所有token的缓存
$this->tokenAuthService->clearCacheOnLogout($user);
// 删除用户的所有token
$user->tokens()->delete();
return $this->Success(['message' => '已登出所有设备']);
}
/**
* 清空认证缓存
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function clearAuthCache(Request $request) : JsonResponse
{
$type = $request->input('type', 'current'); // current, user, all
switch ($type) {
case 'current':
// 清空当前token缓存
$currentToken = $request->bearerToken();
if ($currentToken) {
$result = $this->tokenAuthService->clearTokenCache($currentToken);
return $this->Success([
'message' => '当前token缓存清空成功',
'cleared' => $result
]);
}
return $this->Field('未找到当前token');
case 'user':
// 清空当前用户所有token缓存
$user = $request->user();
$clearedCount = $this->tokenAuthService->clearCacheOnLogout($user);
return $this->Success([
'message' => '用户所有token缓存清空成功',
'cleared_count' => $clearedCount
]);
case 'all':
// 清空所有认证缓存(管理员功能)
$result = $this->tokenAuthService->clearAllAuthCache();
return $this->Success([
'message' => '所有认证缓存清空成功',
'success' => $result
]);
default:
return $this->Field('无效的缓存类型');
}
}
/**
* 获取缓存统计信息
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getCacheStats(Request $request) : JsonResponse
{
$stats = $this->tokenAuthService->getCacheStats();
return $this->Success([
'message' => '缓存统计信息',
'stats' => $stats
]);
}
/**
* 获取当前用户信息
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function me(Request $request) : JsonResponse
{
$user = $request->user();
return $this->Success([
'id' => $user->id,
'username' => $user->username,
'nickname' => $user->nickname,
'email' => $user->email,
'mobile' => $user->mobile,
'avatar' => $user->avatar,
'dept_id' => $user->dept_id,
'login_date' => $user->login_date?->format('Y-m-d H:i:s'),
'login_ip' => $user->login_ip,
'current_token' => [
'name' => $request->user()->currentAccessToken()->name,
'created_at' => $request->user()->currentAccessToken()->created_at->format('Y-m-d H:i:s'),
'last_used_at' => $request->user()->currentAccessToken()->last_used_at?->format('Y-m-d H:i:s'),
]
]);
}
/**
* 刷新Token (删除旧Token创建新Token)
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function refresh(Request $request) : JsonResponse
{
$user = $request->user();
$currentToken = $request->user()->currentAccessToken();
// 获取当前token的设备名
$deviceName = $currentToken->name;
// 删除当前token
$currentToken->delete();
// 创建新token
$newToken = $user->createToken($deviceName);
return $this->Success([
'token' => [
'access_token' => $newToken->plainTextToken,
'token_type' => 'Bearer',
'expires_in' => null,
],
'message' => 'Token刷新成功'
]);
}
/**
* 获取用户所有设备/Token列表
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function devices(Request $request) : JsonResponse
{
$tokens = $request->user()->tokens;
$devices = $tokens->map(function ($token) {
return [
'id' => $token->id,
'name' => $token->name,
'created_at' => $token->created_at->format('Y-m-d H:i:s'),
'last_used_at' => $token->last_used_at?->format('Y-m-d H:i:s'),
'is_current' => $token->id === request()->user()->currentAccessToken()->id,
];
});
return $this->Success([
'devices' => $devices,
'total' => $devices->count()
]);
}
/**
* 删除指定设备/Token
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function deleteDevice(Request $request) : JsonResponse
{
$validator = Validator::make($request->all(), [
'token_id' => ['required', 'integer', 'exists:personal_access_tokens,id']
], [
'token_id.required' => '请指定要删除的Token ID',
'token_id.exists' => 'Token不存在'
]);
if ($validator->fails()) {
return $this->Field($validator->errors()->first(), 422);
}
$tokenId = $request->token_id;
$currentTokenId = $request->user()->currentAccessToken()->id;
// 不能删除当前正在使用的token
if ($tokenId == $currentTokenId) {
return $this->Field('不能删除当前正在使用的设备', 400);
}
// 只能删除自己的token
$deleted = $request->user()->tokens()->where('id', $tokenId)->delete();
if ($deleted) {
return $this->Success(['message' => '设备删除成功']);
} else {
return $this->Field('设备删除失败', 500);
}
}
}