在Laravel项目中如何对用户永久封号,或禁止一段时间
Laravel Auth系统有很多功能,但它不包括对用户封号一段时间,比如对一些不友好的论坛用户禁言14天。使用Middleware可以很轻松的实现。
1. 新字段:users.banned_until
字段类型为:时间戳,如果它是空的,那么用户不被禁止,否则代表禁止到何时。
生成迁移文件:
php artisan make:migration add_banned_until_to_users_table
迁移文件内容:
class AddBannedUntilToUsersTable extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->timestamp('banned_until')->nullable();
});
}
所有已存在的用户都将字段设置为NULL,因此在迁移后不会默认自动禁止任何人。
我们还需要在app/User.php
模型中将该字段添加到$fillable
数组中。为方便起见,我们也将它放入$dates
数组中。稍后会做一些Carbon
操作。
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password', 'banned_until'
];
protected $dates = [
'banned_until'
];
}
我们假设某个管理员某处将users.banned_until的值作为timestamp或NULL。
2. 中间件:CheckBanned
我们将创建一个中间件来检查用户是否被禁止。在这种情况下,我们将该用户注销并重定向到登录页面并显示错误消息。
php artisan make:middleware CheckBanned
这是文件app/Http/Middleware/CheckBanned.php
:
class CheckBanned
{
public function handle($request, Closure $next)
{
if (auth()->check() && auth()->user()->banned_until && now()->lessThan(auth()->user()->banned_until)) {
$banned_days = now()->diffInDays(auth()->user()->banned_until);
auth()->logout();
if ($banned_days > 14) {
$message = 'Your account has been suspended. Please contact administrator.';
} else {
$message = 'Your account has been suspended for '.$banned_days.' '.str_plural('day', $banned_days).'. Please contact administrator.';
}
return redirect()->route('login')->withMessage($message);
}
return $next($request);
}
}
这里有几点需要注意:
- 我们使用一些Carbon方法(如
lessThan()
或diffInDays()
)来执行日期操作。这就是为什么早些时候我们需要在User模型中添加banned_until
字段作为$dates
属性。 - 如果用户被封号14天或更短时间,我们会显示剩余的封号天数。否则我们假设帐户被永久禁止。
- 不确定你是否知道
str_plural()
方法显示名词的单数或复数形式,具体取决于数字。
3. 使用中间件和显示错误消息
接下来,我们需要注册此中间件并在每个请求上运行,因此我们将其类添加到名为web的app/Http/Kernel.php
文件组:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
// ... other middleware classes
\App\Http\Middleware\CheckBanned::class,
],
最后,让我们在resources/views/auth/login.blade.php
中添加消息:
...
<div class="card-body">
@if (session('message'))
<div class="alert alert-danger">{{ session('message') }}</div>
@endif
<form method="POST" action="{{ route('login') }}">
...