新增用户权限信息获取功能,重构设备删除逻辑,优化验证规则,更新路由以支持新功能。同时,添加慢查询日志记录功能,调整缓存配置,完善字典数据服务,更新基础模型以支持软删除。
This commit is contained in:
parent
b43bf56e8e
commit
9b96bae23e
@ -295,29 +295,128 @@ class AuthController extends BaseController
|
||||
$validator = Validator::make($request->all(), [
|
||||
'token_id' => ['required', 'integer', 'exists:personal_access_tokens,id']
|
||||
], [
|
||||
'token_id.required' => '请指定要删除的Token ID',
|
||||
'token_id.exists' => 'Token不存在'
|
||||
'token_id.required' => '请选择要删除的设备',
|
||||
'token_id.exists' => '设备不存在',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->Field($validator->errors()->first(), 422);
|
||||
}
|
||||
|
||||
$tokenId = $request->token_id;
|
||||
$currentTokenId = $request->user()->currentAccessToken()->id;
|
||||
$user = $request->user();
|
||||
$tokenId = $request->input('token_id');
|
||||
|
||||
// 不能删除当前正在使用的token
|
||||
if ($tokenId == $currentTokenId) {
|
||||
return $this->Field('不能删除当前正在使用的设备', 400);
|
||||
// 验证Token属于当前用户
|
||||
$tokenToDelete = $user->tokens()->find($tokenId);
|
||||
if (!$tokenToDelete) {
|
||||
return $this->Field('无权删除此设备Token', 403);
|
||||
}
|
||||
|
||||
// 只能删除自己的token
|
||||
$deleted = $request->user()->tokens()->where('id', $tokenId)->delete();
|
||||
$tokenToDelete->delete();
|
||||
|
||||
if ($deleted) {
|
||||
return $this->Success(['message' => '设备删除成功']);
|
||||
return $this->Success(['message' => '设备删除成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户权限信息
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function permissionInfo(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
// 获取用户角色
|
||||
$userRoles = $user->roles()->where('status', 0)->get();
|
||||
$roleCodes = $userRoles->pluck('code')->toArray();
|
||||
|
||||
// 判断是否为超级管理员(username为admin或角色编码包含admin相关)
|
||||
$isSuperAdmin = $user->username === 'admin' ||
|
||||
in_array('admin', $roleCodes) ||
|
||||
in_array('super_admin', $roleCodes);
|
||||
|
||||
// 获取菜单权限
|
||||
if ($isSuperAdmin) {
|
||||
// 超级管理员获取所有菜单
|
||||
$menus = \App\Models\System\SystemMenu::where('status', 0)
|
||||
->where('visible', 1)
|
||||
->whereIn('type', [1, 2])
|
||||
->orderBy('sort', 'asc')
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
} else {
|
||||
return $this->Field('设备删除失败', 500);
|
||||
// 普通用户根据角色权限获取菜单
|
||||
$roleIds = $userRoles->pluck('id')->toArray();
|
||||
if (empty($roleIds)) {
|
||||
$menus = collect([]);
|
||||
} else {
|
||||
$menuIds = \App\Models\System\SystemRoleMenu::whereIn('role_id', $roleIds)
|
||||
->pluck('menu_id')
|
||||
->unique()
|
||||
->toArray();
|
||||
|
||||
$menus = \App\Models\System\SystemMenu::whereIn('id', $menuIds)
|
||||
->where('status', 0)
|
||||
->where('visible', 1)
|
||||
->whereIn('type', [1, 2])
|
||||
->orderBy('sort', 'asc')
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
|
||||
// 构建菜单树形结构,使用表字段名称而不是驼峰命名
|
||||
$menuTree = $this->buildMenuTree($menus->toArray());
|
||||
|
||||
return $this->SuccessObject([
|
||||
'menus' => $menuTree,
|
||||
'roles' => $roleCodes,
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'nickname' => $user->nickname,
|
||||
'avatar' => $user->avatar ?? '',
|
||||
'dept_id' => $user->dept_id,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树形结构
|
||||
*
|
||||
* @param array $menus
|
||||
* @param int $parentId
|
||||
* @return array
|
||||
*/
|
||||
private function buildMenuTree(array $menus, int $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
foreach ($menus as $menu) {
|
||||
if ($menu['parent_id'] == $parentId) {
|
||||
// 使用表字段名称,不使用驼峰命名
|
||||
$menuItem = [
|
||||
'id' => $menu['id'],
|
||||
'parentId' => $menu['parent_id'],
|
||||
'name' => $menu['name'],
|
||||
'component' => $menu['component'],
|
||||
'componentName' => $menu['component_name'],
|
||||
'icon' => $menu['icon'],
|
||||
'keepAlive' => $menu['keep_alive'],
|
||||
'visible' => $menu['visible'],
|
||||
'alwaysShow' => $menu['always_show'],
|
||||
'path' => $menu['path'],
|
||||
];
|
||||
|
||||
// 递归获取子菜单
|
||||
$children = $this->buildMenuTree($menus, $menu['id']);
|
||||
$menuItem['children'] = $children;
|
||||
|
||||
$tree[] = $menuItem;
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,8 +32,9 @@ class SystemDictDataController extends BaseController
|
||||
*/
|
||||
public function simpleList(SystemDictDataRequest $request): JsonResponse
|
||||
{
|
||||
// 不需要验证
|
||||
$params = $request->validated();
|
||||
$result = $this->systemDictDataService->getByType($params['dict_type'], true);
|
||||
$result = $this->systemDictDataService->getByType($params['dict_type'] ?? '', $params['only_active'] ?? false);
|
||||
return $this->Success($result);
|
||||
}
|
||||
|
||||
|
||||
@ -229,7 +229,7 @@ class SystemDictDataRequest extends BaseRequest
|
||||
private function simpleListRules(): array
|
||||
{
|
||||
return [
|
||||
'dict_type' => ['required', 'string', 'max:100', 'exists:system_dict_type,type'],
|
||||
'dict_type' => ['sometimes', 'string', 'max:100'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -3,16 +3,12 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class BaseModel extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
// 自定义时间戳字段
|
||||
const CREATED_AT = 'create_time';
|
||||
const UPDATED_AT = 'update_time';
|
||||
const DELETED_AT = 'deleted';
|
||||
|
||||
/**
|
||||
* 是否启用系统字段自动维护
|
||||
@ -88,6 +84,54 @@ class BaseModel extends Model
|
||||
return $user ? $user->tenant_id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 软删除(将deleted字段设置为1)
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if ($this->enableSystemFields) {
|
||||
return $this->update(['deleted' => 1]);
|
||||
}
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制删除(真正删除记录)
|
||||
*/
|
||||
public function forceDelete()
|
||||
{
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复软删除的记录
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
if ($this->enableSystemFields) {
|
||||
return $this->update(['deleted' => 0]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含已删除记录的作用域
|
||||
*/
|
||||
public function scopeWithDeleted($query)
|
||||
{
|
||||
return $query->withoutGlobalScope('not_deleted');
|
||||
}
|
||||
|
||||
/**
|
||||
* 只查询已删除记录的作用域
|
||||
*/
|
||||
public function scopeOnlyDeleted($query)
|
||||
{
|
||||
return $query->withoutGlobalScope('not_deleted')->where('deleted', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统字段(创建时)
|
||||
*/
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Database\Events\QueryExecuted;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
@ -19,6 +22,49 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
$this->setupSlowQueryLogging();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置慢查询日志记录
|
||||
*/
|
||||
private function setupSlowQueryLogging(): void
|
||||
{
|
||||
try {
|
||||
DB::listen(function (QueryExecuted $query) {
|
||||
$this->logSlowQuery($query);
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
// 如果SQL日志系统初始化失败,记录到默认日志但不影响主要业务
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 记录慢查询
|
||||
*/
|
||||
private function logSlowQuery(QueryExecuted $query): void
|
||||
{
|
||||
try {
|
||||
// 根据环境设置不同的慢查询阈值, 本地环境所有查询都记录, 正式环境慢查询阈值500ms
|
||||
$slowQueryThreshold = $this->app->environment(['local','development']) ? 0 : 500;
|
||||
|
||||
// 只记录慢查询
|
||||
if ($query->time > $slowQueryThreshold) {
|
||||
Log::channel('sql')->info('Slow Query: ' . $query->sql, [
|
||||
'bindings' => $query->bindings,
|
||||
'time' => $query->time . 'ms',
|
||||
'environment' => $this->app->environment()
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// 慢查询日志记录失败,降级处理
|
||||
Log::error('慢查询日志记录失败', [
|
||||
'query' => $query->sql,
|
||||
'bindings' => $query->bindings,
|
||||
'time' => $query->time . 'ms'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,6 @@ class TokenAuthService
|
||||
try {
|
||||
// 使用Sanctum验证token
|
||||
$accessToken = PersonalAccessToken::findToken($token);
|
||||
|
||||
if (!$accessToken) {
|
||||
return null;
|
||||
}
|
||||
@ -123,7 +122,7 @@ class TokenAuthService
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (!$user->is_active) {
|
||||
if ($user->status != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -72,15 +72,19 @@ class SystemDictDataService extends BaseService
|
||||
* @param bool $onlyActive
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getByType(string $dictType, bool $onlyActive = true)
|
||||
public function getByType(string $dictType = '', bool $onlyActive = true)
|
||||
{
|
||||
$query = SystemDictData::where('dict_type', $dictType);
|
||||
$query = SystemDictData::query();
|
||||
|
||||
if ($dictType) {
|
||||
$query->where('dict_type', $dictType);
|
||||
}
|
||||
|
||||
if ($onlyActive) {
|
||||
$query->where('status', SystemDictData::STATUS_NORMAL);
|
||||
}
|
||||
|
||||
return $query->orderBy('sort')->get();
|
||||
return $query->select('id', 'label', 'value', 'dict_type')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -15,7 +15,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_STORE', 'file'),
|
||||
'default' => env('CACHE_STORE', 'redis'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@ -51,18 +51,18 @@ return [
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => explode(',', (string) env('LOG_STACK', 'single')),
|
||||
'channels' => ['daily'],
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/default/laravel.log'),
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
'permission' => 0664,
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
|
||||
290
database/seeders/SystemMenuSeeder.php
Normal file
290
database/seeders/SystemMenuSeeder.php
Normal file
@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\System\SystemMenu;
|
||||
use App\Models\System\SystemRole;
|
||||
use App\Models\System\SystemRoleMenu;
|
||||
use App\Models\System\SystemUserRole;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SystemMenuSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$creator = 'system';
|
||||
|
||||
// 清空现有数据
|
||||
SystemRoleMenu::query()->delete();
|
||||
SystemUserRole::query()->delete();
|
||||
SystemMenu::query()->delete();
|
||||
SystemRole::query()->delete();
|
||||
|
||||
// 创建角色
|
||||
$adminRole = SystemRole::create([
|
||||
'name' => '超级管理员',
|
||||
'code' => 'superadmin',
|
||||
'sort' => 1,
|
||||
'data_scope' => 1,
|
||||
'status' => 0,
|
||||
'type' => 1,
|
||||
'remark' => '超级管理员角色',
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'updater' => $creator,
|
||||
'update_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
|
||||
$testRole = SystemRole::create([
|
||||
'name' => '测试角色',
|
||||
'code' => 'test',
|
||||
'sort' => 2,
|
||||
'data_scope' => 2,
|
||||
'status' => 0,
|
||||
'type' => 1,
|
||||
'remark' => '测试角色',
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'updater' => $creator,
|
||||
'update_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
|
||||
// 创建菜单数据(参考test.json的结构)
|
||||
$menus = [
|
||||
// 练习模块
|
||||
[
|
||||
'id' => 2972,
|
||||
'name' => '练习',
|
||||
'parent_id' => 0,
|
||||
'type' => 1,
|
||||
'path' => '/exercise',
|
||||
'icon' => 'fa:tree',
|
||||
'component' => null,
|
||||
'component_name' => null,
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'id' => 2892,
|
||||
'name' => '同步教材详情',
|
||||
'parent_id' => 2972,
|
||||
'type' => 2,
|
||||
'path' => 'textbook/catalog',
|
||||
'icon' => 'ep:list',
|
||||
'component' => '/textbook/catalog/index',
|
||||
'component_name' => 'TextbookCatalog',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'id' => 2898,
|
||||
'name' => '同步教材',
|
||||
'parent_id' => 2972,
|
||||
'type' => 2,
|
||||
'path' => 'textbook/catalogList',
|
||||
'icon' => 'fa-solid:book',
|
||||
'component' => '/textbook/catalog/list',
|
||||
'component_name' => null,
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 2,
|
||||
],
|
||||
|
||||
// 基础数据管理模块
|
||||
[
|
||||
'id' => 2808,
|
||||
'name' => '基础数据管理',
|
||||
'parent_id' => 0,
|
||||
'type' => 1,
|
||||
'path' => '/infra-data',
|
||||
'icon' => 'fa-solid:database',
|
||||
'component' => null,
|
||||
'component_name' => null,
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 2,
|
||||
],
|
||||
[
|
||||
'id' => 2930,
|
||||
'name' => '题目列表',
|
||||
'parent_id' => 2808,
|
||||
'type' => 2,
|
||||
'path' => 'question/list',
|
||||
'icon' => 'fa-solid:list-ul',
|
||||
'component' => '/question/index',
|
||||
'component_name' => 'InfraDataQuestion',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 1,
|
||||
],
|
||||
|
||||
// 系统管理模块
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => '系统管理',
|
||||
'parent_id' => 0,
|
||||
'type' => 1,
|
||||
'path' => '/system',
|
||||
'icon' => 'ep:tools',
|
||||
'component' => null,
|
||||
'component_name' => null,
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 10,
|
||||
],
|
||||
[
|
||||
'id' => 100,
|
||||
'name' => '用户管理',
|
||||
'parent_id' => 1,
|
||||
'type' => 2,
|
||||
'path' => 'user',
|
||||
'icon' => 'ep:avatar',
|
||||
'component' => 'system/user/index',
|
||||
'component_name' => 'SystemUser',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'id' => 101,
|
||||
'name' => '角色管理',
|
||||
'parent_id' => 1,
|
||||
'type' => 2,
|
||||
'path' => 'role',
|
||||
'icon' => 'ep:user',
|
||||
'component' => 'system/role/index',
|
||||
'component_name' => 'SystemRole',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 2,
|
||||
],
|
||||
[
|
||||
'id' => 102,
|
||||
'name' => '菜单管理',
|
||||
'parent_id' => 1,
|
||||
'type' => 2,
|
||||
'path' => 'menu',
|
||||
'icon' => 'ep:menu',
|
||||
'component' => 'system/menu/index',
|
||||
'component_name' => 'SystemMenu',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 3,
|
||||
],
|
||||
[
|
||||
'id' => 105,
|
||||
'name' => '字典管理',
|
||||
'parent_id' => 1,
|
||||
'type' => 2,
|
||||
'path' => 'dict',
|
||||
'icon' => 'ep:collection',
|
||||
'component' => 'system/dict/index',
|
||||
'component_name' => 'SystemDictType',
|
||||
'status' => 0,
|
||||
'visible' => 0,
|
||||
'keep_alive' => 1,
|
||||
'always_show' => 1,
|
||||
'sort' => 4,
|
||||
],
|
||||
];
|
||||
|
||||
// 批量插入菜单数据
|
||||
foreach ($menus as $menuData) {
|
||||
$menuData['creator'] = $creator;
|
||||
$menuData['create_time'] = $now;
|
||||
$menuData['updater'] = $creator;
|
||||
$menuData['update_time'] = $now;
|
||||
$menuData['deleted'] = 0;
|
||||
$menuData['tenant_id'] = 1;
|
||||
|
||||
SystemMenu::create($menuData);
|
||||
}
|
||||
|
||||
// 为超级管理员分配所有菜单权限
|
||||
$allMenuIds = SystemMenu::pluck('id')->toArray();
|
||||
foreach ($allMenuIds as $menuId) {
|
||||
SystemRoleMenu::create([
|
||||
'role_id' => $adminRole->id,
|
||||
'menu_id' => $menuId,
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
// 为测试角色只分配部分菜单权限(系统管理模块)
|
||||
$testMenuIds = [1, 100, 101, 102, 105]; // 系统管理相关菜单
|
||||
foreach ($testMenuIds as $menuId) {
|
||||
SystemRoleMenu::create([
|
||||
'role_id' => $testRole->id,
|
||||
'menu_id' => $menuId,
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
// 为现有用户分配角色
|
||||
$adminUser = User::where('username', 'admin')->first();
|
||||
if ($adminUser) {
|
||||
SystemUserRole::create([
|
||||
'user_id' => $adminUser->id,
|
||||
'role_id' => $adminRole->id,
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
$testUser = User::where('username', 'test')->first();
|
||||
if ($testUser) {
|
||||
SystemUserRole::create([
|
||||
'user_id' => $testUser->id,
|
||||
'role_id' => $testRole->id,
|
||||
'creator' => $creator,
|
||||
'create_time' => $now,
|
||||
'deleted' => 0,
|
||||
'tenant_id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->command->info('菜单和角色权限数据创建成功!');
|
||||
$this->command->info('- 创建了超级管理员角色:superadmin(拥有所有菜单权限)');
|
||||
$this->command->info('- 创建了测试角色:test(仅拥有系统管理模块权限)');
|
||||
$this->command->info('- admin用户 -> 超级管理员角色');
|
||||
$this->command->info('- test用户 -> 测试角色');
|
||||
}
|
||||
}
|
||||
@ -39,6 +39,9 @@ Route::middleware('admin.auth')->group(function () {
|
||||
// 获取当前用户信息
|
||||
Route::get('/me', [AuthController::class, 'me'])->name('admin.me');
|
||||
|
||||
// 获取用户权限信息
|
||||
Route::get('/permission/info', [AuthController::class, 'permissionInfo'])->name('admin.permission.info');
|
||||
|
||||
// 刷新Token
|
||||
Route::post('/refresh', [AuthController::class, 'refresh'])->name('admin.refresh');
|
||||
|
||||
@ -52,21 +55,8 @@ Route::middleware('admin.auth')->group(function () {
|
||||
Route::delete('/cache', [AuthController::class, 'clearAuthCache'])->name('admin.cache.clear');
|
||||
Route::get('/cache/stats', [AuthController::class, 'getCacheStats'])->name('admin.cache.stats');
|
||||
|
||||
// 缓存测试(仅开发环境)
|
||||
if (config('app.debug')) {
|
||||
Route::get('/cache/test', function () {
|
||||
$tokenAuthService = app(\App\Services\Auth\TokenAuthService::class);
|
||||
//
|
||||
|
||||
$stats = $tokenAuthService->getCacheStats();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '缓存测试结果',
|
||||
'data' => $stats,
|
||||
'timestamp' => now()->toDateTimeString()
|
||||
]);
|
||||
})->name('admin.cache.test');
|
||||
}
|
||||
});
|
||||
|
||||
// 系统管理模块
|
||||
@ -80,63 +70,4 @@ Route::middleware('admin.auth')->group(function () {
|
||||
Route::delete('role/batch', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'batchDestroy'])->name('admin.system.role.batch.destroy');
|
||||
});
|
||||
|
||||
// 仪表盘数据
|
||||
Route::get('/dashboard', function () {
|
||||
$user = Auth::user();
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'message' => '欢迎来到后台管理系统',
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'nickname' => $user->nickname,
|
||||
],
|
||||
'stats' => [
|
||||
'total_users' => \App\Models\User::count(),
|
||||
'online_users' => 1,
|
||||
'system_info' => [
|
||||
'php_version' => PHP_VERSION,
|
||||
'laravel_version' => app()->version(),
|
||||
]
|
||||
]
|
||||
],
|
||||
'code' => 200,
|
||||
'message' => 'success'
|
||||
]);
|
||||
})->name('admin.dashboard');
|
||||
|
||||
// 异常处理测试路由(仅开发环境)
|
||||
if (config('app.debug')) {
|
||||
Route::prefix('test')->group(function () {
|
||||
// 测试参数验证异常
|
||||
Route::post('/validation', function () {
|
||||
request()->validate([
|
||||
'required_field' => 'required|string',
|
||||
'email_field' => 'required|email',
|
||||
]);
|
||||
return response()->json(['message' => '验证通过']);
|
||||
})->name('admin.test.validation');
|
||||
|
||||
// 测试业务异常
|
||||
Route::get('/business-exception', function () {
|
||||
Handler::throw('测试数据不存在', 404);
|
||||
})->name('admin.test.business');
|
||||
|
||||
// 测试系统异常
|
||||
Route::get('/system-exception', function () {
|
||||
throw new \Exception('测试系统异常');
|
||||
})->name('admin.test.system');
|
||||
|
||||
// 测试参数错误异常
|
||||
Route::get('/param-error', function () {
|
||||
Handler::error('测试参数错误');
|
||||
})->name('admin.test.param');
|
||||
|
||||
// 测试操作失败异常
|
||||
Route::get('/fail', function () {
|
||||
Handler::fail('测试操作失败');
|
||||
})->name('admin.test.fail');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
143
routes/web.php
143
routes/web.php
@ -1,118 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Services\Auth\TokenAuthService;
|
||||
use App\Http\Middleware\AdminApiAuthenticate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
|
||||
// 认证缓存测试路由
|
||||
Route::get('/test-auth-cache', function (TokenAuthService $tokenAuthService) {
|
||||
$output = [];
|
||||
|
||||
$output[] = "=== 认证缓存测试 ===";
|
||||
$output[] = "";
|
||||
|
||||
// 1. 测试服务实例化
|
||||
$output[] = "1. 测试TokenAuthService...";
|
||||
$output[] = "✅ TokenAuthService实例化成功";
|
||||
$output[] = "";
|
||||
|
||||
// 2. 测试缓存状态
|
||||
$output[] = "2. 测试缓存健康状态...";
|
||||
$stats = $tokenAuthService->getCacheStats();
|
||||
|
||||
$output[] = "缓存驱动: " . ($stats['cache_store'] ?? 'unknown');
|
||||
$output[] = "缓存可用: " . ($stats['cache_available'] ? '✅ 是' : '❌ 否');
|
||||
$output[] = "缓存健康: " . ($stats['cache_health'] ? '✅ 正常' : '❌ 异常');
|
||||
$output[] = "缓存前缀: " . $stats['cache_prefix'];
|
||||
$output[] = "默认缓存时间: " . $stats['default_cache_minutes'] . ' 分钟';
|
||||
$output[] = "最大缓存时间: " . $stats['max_cache_minutes'] . ' 分钟';
|
||||
$output[] = "";
|
||||
|
||||
// 3. 测试token验证
|
||||
$output[] = "3. 测试token验证...";
|
||||
$testToken = 'test_invalid_token_123';
|
||||
$user = $tokenAuthService->validateTokenAndGetUser($testToken);
|
||||
|
||||
if ($user === null) {
|
||||
$output[] = "✅ 无效token正确返回null";
|
||||
} else {
|
||||
$output[] = "❌ 无效token验证失败";
|
||||
}
|
||||
$output[] = "";
|
||||
|
||||
// 4. 测试中间件
|
||||
$output[] = "4. 测试中间件功能...";
|
||||
|
||||
// Redis缓存测试路由
|
||||
Route::get('/redis-test', function () {
|
||||
try {
|
||||
// 创建模拟请求
|
||||
$request = Request::create('/admin/auth/me', 'GET');
|
||||
$request->headers->set('Authorization', 'Bearer invalid_token');
|
||||
$request->headers->set('Accept', 'application/json');
|
||||
$results = [];
|
||||
|
||||
// 实例化中间件
|
||||
$middleware = new AdminApiAuthenticate($tokenAuthService);
|
||||
// 测试配置
|
||||
$results['cache_driver'] = config('cache.default');
|
||||
$results['redis_config'] = config('database.redis.cache');
|
||||
|
||||
// 测试中间件
|
||||
$response = $middleware->handle($request, function ($req) {
|
||||
return response()->json(['message' => 'Success']);
|
||||
});
|
||||
// 测试缓存写入
|
||||
$testKey = 'redis_test_' . time();
|
||||
$testValue = 'Hello Redis from Laravel at ' . now();
|
||||
|
||||
if ($response->getStatusCode() === 401) {
|
||||
$output[] = "✅ 中间件正确返回401错误";
|
||||
$responseData = json_decode($response->getContent(), true);
|
||||
$output[] = "响应消息: " . ($responseData['message'] ?? 'unknown');
|
||||
} else {
|
||||
$output[] = "❌ 中间件未正确处理无效token";
|
||||
}
|
||||
Cache::put($testKey, $testValue, 60);
|
||||
$results['write_test'] = '✓ 成功';
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$output[] = "❌ 中间件测试失败: " . $e->getMessage();
|
||||
// 测试缓存读取
|
||||
$readValue = Cache::get($testKey);
|
||||
$results['read_test'] = $readValue === $testValue ? '✓ 成功' : '✗ 失败';
|
||||
$results['read_value'] = $readValue;
|
||||
|
||||
// 测试缓存删除
|
||||
$deleted = Cache::forget($testKey);
|
||||
$results['delete_test'] = $deleted ? '✓ 成功' : '✗ 失败';
|
||||
|
||||
// 验证删除
|
||||
$afterDelete = Cache::get($testKey);
|
||||
$results['delete_verification'] = $afterDelete === null ? '✓ 成功' : '✗ 失败';
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Redis缓存测试完成',
|
||||
'results' => $results
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Redis缓存测试失败',
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
], 500);
|
||||
}
|
||||
$output[] = "";
|
||||
|
||||
// 5. 缓存性能测试
|
||||
$output[] = "5. 缓存性能测试...";
|
||||
|
||||
if ($stats['cache_health']) {
|
||||
$startTime = microtime(true);
|
||||
|
||||
// 模拟多次缓存操作
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$tokenAuthService->validateTokenAndGetUser('test_token_' . $i);
|
||||
}
|
||||
|
||||
$endTime = microtime(true);
|
||||
$duration = round(($endTime - $startTime) * 1000, 2);
|
||||
|
||||
$output[] = "✅ 完成10次token验证,耗时: {$duration}ms";
|
||||
} else {
|
||||
$output[] = "⚠️ 缓存不可用,跳过性能测试";
|
||||
}
|
||||
$output[] = "";
|
||||
|
||||
$output[] = "=== 测试完成 ===";
|
||||
|
||||
// 总结
|
||||
$cacheStatus = $stats['cache_health'] ? '正常工作' : '使用数据库回退';
|
||||
|
||||
$output[] = "";
|
||||
$output[] = "组件状态总结:";
|
||||
$output[] = "- 缓存功能: " . $cacheStatus;
|
||||
$output[] = "- 中间件: ✅ 正常工作";
|
||||
$output[] = "- Token验证: ✅ 正常工作";
|
||||
$output[] = "- 异常处理: ✅ 正常工作";
|
||||
$output[] = "";
|
||||
|
||||
$output[] = "提示:如果要启用Redis缓存,请确保:";
|
||||
$output[] = "1. Redis服务正在运行";
|
||||
$output[] = "2. 在.env文件中设置 CACHE_STORE=redis";
|
||||
$output[] = "3. 在.env文件中设置 REDIS_CLIENT=predis";
|
||||
|
||||
return response('<pre>' . implode("\n", $output) . '</pre>')
|
||||
->header('Content-Type', 'text/html; charset=utf-8');
|
||||
});
|
||||
})->name('redis.test');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user