功能:禁用用户名管理(永久禁词列表)

数据库:
- 新增迁移 username_blacklist 表加 type/reason 列
  type: temp(改名30天保留)| permanent(管理员永久禁用)
  reason: 禁用原因备注(最长100字符)

核心逻辑:
- UsernameBlacklist::isBlocked() 同时拦截两种类型
  也包含 isReserved() 兼容旧调用
  增加 scopePermanent()/scopeTemp() 查询作用域
- AuthController 注册时加 isBlocked() 拦截
  禁词/保留期内均不可注册
- ShopService::useRenameCard() 已有 isReserved() 调用
  因已改用 isBlocked() 别名,无需修改

后台:
- ForbiddenUsernameController:index/store/update/destroy
- 路由:/admin/forbidden-usernames(chat.site_owner 中间件)
- 视图:admin/forbidden-usernames/index.blade.php
  新增表单、关键词搜索、分页、行内编辑原因、删除
- 侧边栏加「🚫 禁用用户名」入口(仅站长可见)
This commit is contained in:
2026-03-01 14:00:38 +08:00
parent 312b92a81d
commit fc495ccceb
7 changed files with 462 additions and 13 deletions

View File

@@ -0,0 +1,115 @@
<?php
/**
* 文件功能:禁用用户名管理控制器(站长专用)
*
* 管理 username_blacklist 表中 type=permanent 的永久禁用词列表。
* 包含:国家领导人名称、攻击性词汇、违禁词等不允许注册或改名的词语。
*
* 用户在注册AuthController和改名ShopService::useRenameCard时均会经过该表检测。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\UsernameBlacklist;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
class ForbiddenUsernameController extends Controller
{
/**
* 分页列出所有永久禁用词。
* 支持关键词模糊搜索GET ?q=xxx
*/
public function index(Request $request): \Illuminate\View\View
{
$q = $request->query('q', '');
$items = UsernameBlacklist::permanent()
->when($q, fn ($query) => $query->where('username', 'like', "%{$q}%"))
->orderByDesc('created_at')
->paginate(20)
->withQueryString();
return view('admin.forbidden-usernames.index', [
'items' => $items,
'q' => $q,
]);
}
/**
* 新增一条永久禁用词。
*
* @param Request $request 请求体username必填reason选填
*/
public function store(Request $request): JsonResponse
{
$validated = $request->validate([
'username' => ['required', 'string', 'max:50'],
'reason' => ['nullable', 'string', 'max:100'],
], [
'username.required' => '禁用词不能为空。',
'username.max' => '禁用词最长50字符。',
]);
$username = trim($validated['username']);
// 已存在同名的永久记录则不重复插入
$exists = UsernameBlacklist::permanent()
->where('username', $username)
->exists();
if ($exists) {
return response()->json(['status' => 'error', 'message' => '该词语已在永久禁用列表中。'], 422);
}
UsernameBlacklist::create([
'username' => $username,
'type' => 'permanent',
'reserved_until' => null,
'reason' => $validated['reason'] ?? null,
'created_at' => Carbon::now(),
]);
return response()->json(['status' => 'success', 'message' => "{$username}」已加入永久禁用列表。"]);
}
/**
* 更新指定禁用词的原因备注。
*
* @param int $id 记录 ID
* @param Request $request 请求体reason
*/
public function update(Request $request, int $id): JsonResponse
{
$item = UsernameBlacklist::permanent()->findOrFail($id);
$validated = $request->validate([
'reason' => ['nullable', 'string', 'max:100'],
]);
$item->update(['reason' => $validated['reason']]);
return response()->json(['status' => 'success', 'message' => '备注已更新。']);
}
/**
* 删除指定永久禁用词。
*
* @param int $id 记录 ID
*/
public function destroy(int $id): JsonResponse
{
$item = UsernameBlacklist::permanent()->findOrFail($id);
$name = $item->username;
$item->delete();
return response()->json(['status' => 'success', 'message' => "{$name}」已从永久禁用列表移除。"]);
}
}

View File

@@ -11,10 +11,11 @@
namespace App\Http\Controllers;
use App\Http\Requests\LoginRequest;
use App\Models\Sysparam;
use App\Models\User;
use App\Models\UsernameBlacklist;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Models\Sysparam;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redis;
@@ -99,6 +100,11 @@ class AuthController extends Controller
return response()->json(['status' => 'error', 'message' => '您所在的 IP 地址已被管理员封禁,禁止注册新账号。'], 403);
}
// 检测用户名是否在禁用词列表(永久禁用 或 改名临时保留期内)
if (UsernameBlacklist::isBlocked($username)) {
return response()->json(['status' => 'error', 'message' => '该用户名已被系统禁止注册,请更换其他名称。'], 422);
}
$newUser = User::create([
'username' => $username,
'password' => Hash::make($password),
@@ -123,7 +129,7 @@ class AuthController extends Controller
// 递增访问次数
$user->increment('visit_num');
// 更新最后登录IP和时间
$user->update([
'last_ip' => $ip,