账户禁用是 Web 应用程序中限制用户访问(永久或临时)的常见需求。Laravel 使用数据库字段、中间件和计划任务提供了一种灵活的方式来实现此功能。本指南涵盖了永久禁用和临时禁用两种方式。
永久禁用
被永久禁用的用户将被阻止访问应用程序,直到被手动解除禁用。
1. 向 users 表添加禁用字段
为了追踪用户是否被禁用,向 users
表添加一个 suspended_at
列:
Schema::table('users', function (Blueprint $table) {
// 添加一个可为空的时间戳字段,用于记录禁用时间
$table->timestamp('suspended_at')->nullable();
});
2. 更新 User 模型
在 User
模型中定义一个方法来检查用户是否被禁用:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/**
* 检查用户账户是否已被禁用。
*
* @return bool
*/
public function suspended(): bool
{
// 如果 suspended_at 字段不为 null,则表示用户已被禁用
return !is_null($this->suspended_at);
}
}
3. 使用中间件限制被禁用的用户
为了阻止被禁用用户的访问,创建一个名为 CheckSuspended
的中间件:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckSuspended
{
/**
* 处理传入的请求。
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
// 检查用户是否已登录,并且其账户是否被禁用
if (auth()->check() && auth()->user()->suspended()) {
// 如果账户被禁用,则中止请求并返回 403 错误
abort(403, '您的账户已被禁用。'); // Your account is suspended.
}
// 如果账户未被禁用,则继续处理请求
return $next($request);
}
}
别忘了在 app/Http/Kernel.php
中注册这个中间件,并将其应用到需要保护的路由组上。
4. 禁用和解禁用户
在控制器中实现函数来禁用和解禁用户:
use App\Models\User;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
// 禁用用户
public function suspend(User $user): JsonResponse
{
$user->update([
'suspended_at' => Carbon::now(), // 设置禁用时间为当前时间
]);
return response()->json(['message' => '用户禁用成功。']); // User suspended successfully.
}
// 解禁用户
public function unsuspend(User $user): JsonResponse
{
$user->update([
'suspended_at' => null, // 清除禁用时间
]);
return response()->json(['message' => '用户解禁成功。']); // User unsuspended successfully.
}
临时禁用
对于临时禁用,我们存储一个 suspended_until
时间戳而不是 suspended_at
,以允许自动重新激活。
1. 修改 users 表
添加一个 suspended_until
列:
Schema::table('users', function (Blueprint $table) {
// 添加一个可为空的时间戳字段,用于记录禁用截止时间
$table->timestamp('suspended_until')->nullable();
});
注意:如果您同时需要永久和临时禁用,您可以保留 suspended_at
并添加 suspended_until
,或者使用一个字段和一个额外的 suspension_type
字段来区分。本例假设只使用 suspended_until
实现临时禁用。如果需要同时支持,需要调整模型和中间件逻辑。
2. 更新 User 模型
修改 suspended()
方法以检查禁用是否仍然有效(即当前时间是否早于 suspended_until
):
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Carbon;
class User extends Authenticatable
{
/**
* 检查用户账户当前是否处于临时禁用状态。
*
* @return bool
*/
public function suspended(): bool
{
// 检查 suspended_until 是否设置,并且当前时间是否在禁用截止时间之前
return !is_null($this->suspended_until) && Carbon::now()->lessThan($this->suspended_until);
}
}
3. 使用中间件限制被禁用的用户
中间件 CheckSuspended
的逻辑保持不变,因为它调用的是 auth()->user()->suspended()
方法。该方法现在会根据 suspended_until
的值和当前时间来判断用户是否应被视为已禁用。
// 中间件 CheckSuspended (与永久禁用中的相同)
public function handle(Request $request, Closure $next)
{
if (auth()->check() && auth()->user()->suspended()) {
// 如果 suspended() 返回 true (基于 suspended_until 的检查),则中止
abort(403, '您的账户已被临时禁用。'); // Your account is temporarily suspended.
}
return $next($request);
}
4. 临时禁用和解禁用户
为临时禁用设置一个未来的时间戳:
use App\Models\User;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
// 临时禁用用户(例如,禁用 7 天)
public function suspend(User $user): JsonResponse
{
$user->update([
'suspended_until' => Carbon::now()->addDays(7), // 设置禁用截止时间为 7 天后
]);
return response()->json(['message' => '用户已被临时禁用 7 天。']); // User suspended for 7 days.
}
// 手动解禁用户(提前解除临时禁用)
public function unsuspend(User $user): JsonResponse
{
$user->update([
'suspended_until' => null, // 清除禁用截止时间
]);
return response()->json(['message' => '用户解禁成功。']); // User unsuspended successfully.
}
5. 通过调度器自动解禁用户
由于临时禁用会自动到期,我们可以使用计划任务来清理(解除)已到期的禁用。
首先,创建一个 Artisan 命令: php artisan make:command SuspendClear
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
class SuspendClear extends Command
{
/**
* 控制台命令的名称和签名。
*
* @var string
*/
protected $signature = 'suspend:clear'; // 命令签名
/**
* 控制台命令描述。
*
* @var string
*/
protected $description = '自动解除已到期的临时用户禁用'; // Command description
/**
* 执行控制台命令。
*
* @return int
*/
public function handle()
{
$this->info('正在清理已到期的用户禁用...');
// 查找 suspended_until 不为空且小于等于当前时间的记录
$count = User::whereNotNull('suspended_until')
->where('suspended_until', '<=', Carbon::now())
->update([
'suspended_until' => null, // 将 suspended_until 设置为 null 以解除禁用
]);
$this->info("成功解禁了 {$count} 个用户。");
return Command::SUCCESS;
}
}
将此 suspend:clear
命令添加到调度器,使其定期运行(例如,每小时),在 routes/console.php
文件内配置:
use Illuminate\Support\Facades\Schedule;
/**
* 定义应用程序的命令调度。
* 运行调度器需要执行: php artisan schedule:work (用于本地开发测试)
* 或在服务器上配置 Cron Job: * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
*/
Schedule::command('suspend:clear')->hourly(); // 每小时运行一次 suspend:clear 命令
总结
本指南演示了如何在 Laravel 中实现永久和临时账户禁用,主要使用了:
- 数据库列(
suspended_at
或 suspended_until
)。
- 中间件(
CheckSuspended
)来限制访问。
- 控制器方法来管理禁用状态。
- 计划任务 (
SuspendClear
命令) 来自动解除临时禁用。
通过整合这些步骤,您可以有效地管理用户访问权限,并确保应用程序符合您的管理策略。