validate([ 'username' => ['required', 'string', 'max:64'], 'password' => ['required', 'string', 'max:255'], ]); $admin = AdminUser::query()->where('username', $data['username'])->first(); if (! $admin || ! Hash::check($data['password'], $admin->password_hash)) { throw ValidationException::withMessages([ 'username' => ['账号或密码错误'], ]); } if ((int) $admin->status !== 1) { $this->recordLoginOperationLog($admin, $request, $started, 403); return $this->fail('账号已停用', 403); } $admin->forceFill([ 'last_login_at' => now(), 'last_login_ip' => $request->ip(), ])->save(); $admin->tokens()->delete(); $token = $admin->createToken('admin-api')->plainTextToken; $this->recordLoginOperationLog($admin, $request, $started, 200); return $this->ok([ 'token' => $token, 'token_type' => 'Bearer', 'user' => $this->userPayload($admin), ]); } /** * 登录时请求尚未通过 Sanctum 认证,操作日志中间件无法识别用户,故在控制器内单独写入。 */ protected function recordLoginOperationLog( AdminUser $admin, Request $request, float $startedAt, int $responseCode, ): void { OperationLog::query()->create([ 'admin_user_id' => $admin->id, 'operator_name' => $admin->real_name ?: $admin->username, 'operated_at' => now(), 'http_method' => 'POST', 'api_path' => '/'.$request->path(), 'action_label' => $responseCode === 200 ? '管理员登录' : '管理员登录拒绝(账号停用)', 'ip' => $request->ip(), 'user_agent' => Str::limit((string) $request->userAgent(), 512, ''), 'request_summary' => ['username' => $admin->username], 'response_code' => $responseCode, 'duration_ms' => (int) round((microtime(true) - $startedAt) * 1000), ]); } public function logout(Request $request): JsonResponse { $request->user()?->currentAccessToken()?->delete(); return $this->ok(null, '已退出'); } public function me(Request $request): JsonResponse { /** @var AdminUser $admin */ $admin = $request->user(); $admin->load('roles'); return $this->ok([ 'user' => $this->userPayload($admin), 'permissions' => $admin->permissionCodes(), 'menus' => $this->menuService->treeForUser($admin), ]); } public function changePassword(Request $request): JsonResponse { $data = $request->validate([ 'password' => ['required', 'string', 'min:6', 'max:255', 'confirmed'], ]); /** @var AdminUser $admin */ $admin = $request->user(); $admin->forceFill([ 'password_hash' => Hash::make($data['password']), ])->save(); return $this->ok(null, '密码已更新'); } /** @return array */ protected function userPayload(AdminUser $admin): array { return [ 'id' => $admin->id, 'username' => $admin->username, 'real_name' => $admin->real_name, 'mobile' => $admin->mobile, 'email' => $admin->email, 'avatar_url' => $admin->avatar_url, 'status' => (int) $admin->status, 'roles' => $admin->roles->map(fn ($r) => [ 'id' => $r->id, 'code' => $r->code, 'name' => $r->name, ])->values()->all(), 'is_super_admin' => $admin->isSuperAdmin(), 'is_grid_member' => $this->gridScope->isGridMember($admin), 'grid_scope' => $this->gridScope->isGridMember($admin) ? $this->gridScope->scopePayload($admin) : null, ]; } }