本文目录导读:

我来为你提供一个完整的 PHP 封禁状态检查中间件实现:
基础中间件实现
<?php
namespace App\Middleware;
use Closure;
use App\Models\User;
use App\Services\BanService;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckBanStatusMiddleware
{
protected $banService;
public function __construct(BanService $banService)
{
$this->banService = $banService;
}
public function handle(Request $request, Closure $next, string $type = 'user'): Response
{
// 获取当前认证用户
$user = $request->user();
if (!$user) {
return $next($request);
}
// 检查用户是否被封禁
if ($this->isUserBanned($user, $type)) {
return $this->handleBannedUser($request, $user);
}
// 检查IP是否被封禁
if ($this->isIpBanned($request->ip())) {
return $this->handleBannedIp($request);
}
return $next($request);
}
protected function isUserBanned($user, string $type): bool
{
// 检查用户是否有封禁记录
$ban = $user->bans()
->where('type', $type)
->where(function ($query) {
$query->whereNull('expires_at')
->orWhere('expires_at', '>', now());
})
->latest()
->first();
if (!$ban) {
return false;
}
// 检查是否永久封禁或临时封禁
if ($ban->is_permanent || $ban->expires_at > now()) {
return true;
}
return false;
}
protected function isIpBanned(string $ip): bool
{
return $this->banService->isIpBanned($ip);
}
protected function handleBannedUser($request, $user): Response
{
if ($request->expectsJson()) {
return response()->json([
'success' => false,
'message' => '您的账号已被封禁',
'data' => [
'ban_reason' => $user->currentBan?->reason,
'ban_until' => $user->currentBan?->expires_at,
'is_permanent' => $user->currentBan?->is_permanent ?? false
]
], 403);
}
// 注销用户会话
auth()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()
->route('banned')
->with('error', '您的账号已被封禁');
}
protected function handleBannedIp($request): Response
{
if ($request->expectsJson()) {
return response()->json([
'success' => false,
'message' => '当前IP已被封禁'
], 403);
}
abort(403, '当前IP已被封禁');
}
}
封禁服务类
<?php
namespace App\Services;
use App\Models\User;
use App\Models\BanRecord;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
class BanService
{
/**
* 检查用户是否被封禁
*/
public function checkUserBan(User $user): ?BanRecord
{
return $user->bans()
->where(function ($query) {
$query->whereNull('expires_at')
->orWhere('expires_at', '>', now());
})
->where('is_active', true)
->latest()
->first();
}
/**
* 检查IP是否被封禁
*/
public function isIpBanned(string $ip): bool
{
// 使用缓存减少数据库查询
return Cache::remember("banned_ip:{$ip}", 3600, function () use ($ip) {
return BanRecord::where('ip_address', $ip)
->where('type', 'ip')
->where(function ($query) {
$query->whereNull('expires_at')
->orWhere('expires_at', '>', now());
})
->where('is_active', true)
->exists();
});
}
/**
* 封禁用户
*/
public function banUser(User $user, array $data): BanRecord
{
$ban = $user->bans()->create([
'type' => 'user',
'reason' => $data['reason'],
'expires_at' => $data['duration'] === 'permanent' ? null
: now()->addDays($data['duration']),
'is_permanent' => $data['duration'] === 'permanent',
'banned_by' => auth()->id(),
'ip_address' => request()->ip()
]);
// 清除相关缓存
$this->clearUserBanCache($user->id);
$this->clearIpBanCache(request()->ip());
return $ban;
}
/**
* 解除封禁
*/
public function unbanUser(int $userId): bool
{
$updated = BanRecord::where('user_id', $userId)
->where('is_active', true)
->update(['is_active' => false]);
$this->clearUserBanCache($userId);
return $updated > 0;
}
/**
* 封禁IP
*/
public function banIp(string $ip, array $data): BanRecord
{
$ban = BanRecord::create([
'type' => 'ip',
'ip_address' => $ip,
'reason' => $data['reason'] ?? 'IP封禁',
'expires_at' => $data['duration'] === 'permanent' ? null
: now()->addDays($data['duration']),
'is_permanent' => $data['duration'] === 'permanent',
'banned_by' => auth()->id()
]);
$this->clearIpBanCache($ip);
return $ban;
}
/**
* 检查登录尝试次数
*/
public function checkLoginAttempts(string $email, string $ip): array
{
$key = "login_attempts:{$email}:{$ip}";
$attempts = Redis::get($key) ?: 0;
$maxAttempts = 5;
return [
'attempts' => (int)$attempts,
'remaining' => max(0, $maxAttempts - (int)$attempts),
'is_locked' => (int)$attempts >= $maxAttempts
];
}
/**
* 记录登录失败
*/
public function recordLoginFailure(string $email, string $ip): void
{
$key = "login_attempts:{$email}:{$ip}";
$attempts = Redis::get($key) ?: 0;
Redis::setex($key, 3600, (int)$attempts + 1);
}
/**
* 清除登录失败记录
*/
public function clearLoginAttempts(string $email, string $ip): void
{
Redis::del("login_attempts:{$email}:{$ip}");
}
protected function clearUserBanCache(int $userId): void
{
Cache::forget("user_ban:{$userId}");
Cache::forget('user_ban_status:'.$userId);
}
protected function clearIpBanCache(string $ip): void
{
Cache::forget("banned_ip:{$ip}");
}
}
用户模型添加封禁关系
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Model
{
public function bans(): HasMany
{
return $this->hasMany(BanRecord::class);
}
public function currentBan(): ?BanRecord
{
return $this->bans()
->where(function ($query) {
$query->whereNull('expires_at')
->orWhere('expires_at', '>', now());
})
->where('is_active', true)
->latest()
->first();
}
public function isBanned(): bool
{
return $this->currentBan() !== null;
}
}
封禁记录模型
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BanRecord extends Model
{
protected $fillable = [
'user_id',
'type',
'reason',
'expires_at',
'is_permanent',
'is_active',
'ip_address',
'banned_by',
'created_at',
'updated_at'
];
protected $casts = [
'expires_at' => 'datetime',
'is_permanent' => 'boolean',
'is_active' => 'boolean'
];
protected $dates = ['expires_at'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function bannedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'banned_by');
}
}
路由注册中间件
<?php
// routes/web.php 或 routes/api.php
use App\Middleware\CheckBanStatusMiddleware;
// Web 路由
Route::middleware(['auth', CheckBanStatusMiddleware::class])->group(function () {
Route::get('/dashboard', 'DashboardController@index');
// 其他需要检查封禁状态的路由
});
// API 路由
Route::middleware(['auth:sanctum', CheckBanStatusMiddleware::class])->group(function () {
Route::get('/api/user/profile', 'Api\UserController@profile');
// 其他API路由
});
// 自定义封禁类型
Route::middleware(['auth', 'ban.check:shop'])->group(function () {
// 商店相关路由
});
使用示例
<?php
// 在控制器中使用
namespace App\Http\Controllers;
use App\Services\BanService;
class AdminController extends Controller
{
protected $banService;
public function __construct(BanService $banService)
{
$this->banService = $banService;
}
public function banUser(Request $request, $userId)
{
$user = User::findOrFail($userId);
$ban = $this->banService->banUser($user, [
'reason' => $request->reason,
'duration' => $request->duration // 'permanent' 或天数
]);
return response()->json([
'success' => true,
'message' => '用户已被封禁',
'data' => $ban
]);
}
public function unbanUser($userId)
{
$this->banService->unbanUser($userId);
return response()->json([
'success' => true,
'message' => '用户封禁已解除'
]);
}
}
封禁页面视图(Blade)
{{-- resources/views/banned.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header bg-danger text-white">
<h3><i class="fas fa-ban"></i> 账号封禁通知</h3>
</div>
<div class="card-body">
@if(session('error'))
<div class="alert alert-danger">
{{ session('error') }}
</div>
@endif
<p>您的账号已被封禁,如果这是误判,请联系管理员申诉。</p>
@if(isset($banReason))
<p><strong>封禁原因:</strong>{{ $banReason }}</p>
@endif
@if(isset($banUntil))
<p><strong>封禁至:</strong>{{ $banUntil->format('Y-m-d H:i:s') }}</p>
@endif
<a href="{{ route('home') }}" class="btn btn-primary">返回首页</a>
</div>
</div>
</div>
</div>
</div>
@endsection
配置封禁选项
<?php
// config/ban.php
return [
'types' => [
'user' => '用户封禁',
'ip' => 'IP封禁',
'shop' => '店铺封禁',
],
'durations' => [
'1' => '1天',
'3' => '3天',
'7' => '7天',
'30' => '30天',
'permanent' => '永久',
],
'max_login_attempts' => 5,
'login_lockout_minutes' => 60,
];
这个中间件系统包含了:
- 完整的封禁检查逻辑
- 用户和IP双重检查
- JSON和Web响应支持
- 缓存优化性能
- 灵活的封禁类型
- 封禁和解封管理
- 登录限制功能
你可以根据实际需求调整封禁逻辑和响应方式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播