精华 XIUNOX 用户封禁系统

贰先生 管理 48分钟前

1. 概述

用户封禁系统是 Xiuno BBS 4.5+ 的核心安全模块,提供 4 档用户状态管理,用于对付恶意用户(小黑子)。系统采用「核心实现 + 事件扩展」架构:核心逻辑在 lib/UserBanService.php,插件通过 lib/XnEvent.php 事件机制接入。

核心特性

  • 4 档封禁状态:正常 / 禁言 / 禁止访问 / 锁定

  • 场景化检查:login / browse / post / password 四种入口分别拦截不同 ban_type

  • 到期自动解封:访问时检查 banned_until,过期自动重置字段

  • 封禁历史:完整记录 ban / unban / auto_unban / clear_content 操作

  • IP 黑名单:支持单 IP 与 IP 段(范围)封禁

  • 版主权限分级:版主仅能禁言 1-7 天,管理员可永久 / 锁定

  • 内容清空:保留账号、清空回帖/主题索引/附件/通知

  • 前台内容隐藏:被封用户发布的内容显示占位提示,管理员可见原始内容

  • 封禁公示页:双栏展示当前封禁与近期释放用户

  • 事件机制:6 个 XnEvent 事件 + 3 个 PHP hook 点供插件扩展

设计原则

  • 永久封禁时间戳用 9999999999(约 2286 年),避免 32 位系统 PHP_INT_MAX 溢出

  • 不可封禁管理员组(gid=1,2)和封禁操作者自己

  • ban_type 等字段不在 USER_UPDATE_PROTECTED_FIELDS 中,可用 user_update() 而非 user__update(),前者会自动清缓存 + 触发 hook

  • 通知函数是 notify_create()(非 notice_send()),用 type='system' + from_uid=0 允许系统通知自己

2. 数据库设计

2.1 user 表扩展字段

ALTER TABLE `bbs_user`
  ADD COLUMN `ban_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '封禁类型 0正常/1禁言/2禁止访问/3锁定',
  ADD COLUMN `ban_reason` varchar(255) NOT NULL DEFAULT '' COMMENT '封禁原因',
  ADD COLUMN `ban_admin_uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '封禁操作管理员uid',
  ADD COLUMN `ban_time` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '封禁时间';
-- 复用已有 banned_until 字段:0=未封禁,9999999999=永久,其他=到期时间戳

字段

类型

说明

ban_type

tinyint(1)

0 正常 / 1 禁言 / 2 禁止访问 / 3 锁定

banned_until

int(11) unsigned

复用已有字段。0=未封禁,9999999999=永久,其他=到期 Unix 时间戳

ban_reason

varchar(255)

封禁原因,显示给用户和后台

ban_admin_uid

int(11) unsigned

执行封禁的管理员 uid(系统自动解封时为 0)

ban_time

int(11) unsigned

最近一次封禁时间

2.2 bbs_user_ban_log 表(封禁历史)

CREATE TABLE `bbs_user_ban_log` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '被操作用户uid',
  `admin_uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '操作管理员uid(0=系统自动)',
  `action` varchar(16) NOT NULL DEFAULT '' COMMENT 'ban/unban/auto_unban/clear_content',
  `ban_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '封禁类型(unban/auto_unban/clear_content时为0)',
  `reason` varchar(255) NOT NULL DEFAULT '' COMMENT '原因',
  `duration` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '封禁时长秒数(0=永久)',
  `create_time` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '操作时间',
  PRIMARY KEY (id),
  KEY uid (uid),
  KEY action_time (action, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

action 取值

  • ban — 手动封禁

  • unban — 手动解封

  • auto_unban — 到期系统自动解封(不发通知)

  • clear_content — 清空用户内容

2.3 bbs_banned_ip 表(IP 黑名单)

CREATE TABLE `bbs_banned_ip` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `ip_start` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '起始IP(ip2long整型)',
  `ip_end` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '结束IP(ip2long整型)',
  `reason` varchar(255) NOT NULL DEFAULT '' COMMENT '封禁原因',
  `admin_uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '操作管理员uid',
  `create_time` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
  `expire_time` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '过期时间戳(0=永久)',
  PRIMARY KEY (id),
  KEY ip_range (ip_start, ip_end)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

注意ip_start/ip_end 字段为整型,写入必须用 ip2long() + sprintf('%u', ...) 处理 32 位系统溢出。读取显示时用 long2ip() 还原。

3. 配置项

conf/conf.default.php 中:

配置项

类型

默认值

说明

ban_show_public_list

int

1

是否开启封禁公示页(/banned)。0 关闭(访问返回 404),1 开启

ban_inherit_to_same_ip

int

0

预留:是否对同 IP 用户继承封禁状态。当前未启用,供插件实现

4. UserBanService API

文件位置:lib/UserBanService.php

4.1 常量

UserBanService::BAN_TYPE_NORMAL     = 0;  // 正常
UserBanService::BAN_TYPE_SILENCE     = 1;  // 禁言(可浏览,不能发帖回帖)
UserBanService::BAN_TYPE_BAN_ACCESS  = 2;  // 禁止访问(不能登录、不能浏览)
UserBanService::BAN_TYPE_LOCK        = 3;  // 锁定(不能登录、不能改密找密)

UserBanService::PERMANENT_BAN       = 9999999999;  // 永久封禁时间戳(约2286年)
UserBanService::ADMIN_GIDS           = [1, 2];      // 管理员组 gid(不可被封禁/清空内容)

4.2 静态方法

ban($uid, $banType, $duration, $reason, $adminUid) — 封禁用户

$result = UserBanService::ban(
    $uid,                              // 被封禁用户 uid
    UserBanService::BAN_TYPE_SILENCE,  // 封禁类型 1/2/3
    86400 * 7,                         // 时长秒数,0=永久
    '广告灌水',                         // 封禁原因
    $adminUid                          // 操作管理员 uid
);
// 返回 ['code'=>0 成功, 'message'=>错误信息]

校验

  • $uid > 0$adminUid > 0

  • $banType 必须是 1/2/3

  • $duration >= 0(0=永久)

  • 不能封禁自己($uid === $adminUid

  • 不能封禁管理员组(gid ∈ ADMIN_GIDS)

  • user 表必须有 ban_type 字段(升级后才有)

流程:触发 beforeBan 事件 → 更新 user 表 → 写 ban_log(action=ban)→ 发送通知 → 触发 afterBan 事件。

unban($uid, $adminUid, $reason = '') — 解封用户

$result = UserBanService::unban($uid, $adminUid, '申诉通过');

流程:触发 beforeUnban → 重置 5 个封禁字段为 0/空 → 写 ban_log(action=unban)→ 发送通知 → 触发 afterUnban

checkBan($uid) — 检查封禁状态(含到期自动解封)

$status = UserBanService::checkBan($uid);
// 返回 ['banned'=>bool, 'ban_type'=>int, 'ban_reason'=>string, 'expire_time'=>int, 'expire_formatted'=>string]

自动解封:若 banned_until > 0<= time(),自动调用 autoUnban() 重置字段并写日志(action=auto_unban,不发通知),返回 banned=false

checkBanByScene($uid, $scene) — 按场景检查(用于入口拦截)

$check = UserBanService::checkBanByScene($uid, 'post');
if(!$check['allowed']) {
    message(-1, $check['message']);
}

场景规则

Scene

拒绝的 ban_type

用途

login

2, 3

禁止访问 / 锁定 不能登录

browse

2, 3

禁止访问 / 锁定 不能浏览

post

1, 2, 3

禁言及以上不能发帖回帖编辑

password

3

锁定 不能改密找密

其他

1, 2, 3

未知场景保守拒绝所有

clearContent($uid, $adminUid) — 清空用户内容(保留账号)

$result = UserBanService::clearContent($uid, $adminUid);

清理范围

  • 删除所有回帖(post_delete_by_uid

  • 删除主题索引(mythread_delete_by_uid,不删 thread 表主题记录,已知天花板见代码注释)

  • 删除附件(attach_delete_by_uid

  • 删除通知(notify_delete_by_uid

  • 重置 threads / posts 计数为 0

流程:触发 beforeClearContent → 删除内容 → 重置计数 → 写 ban_log(action=clear_content)→ 触发 afterClearContent不发通知

getBanStatus($uid) — 获取格式化封禁状态(前端显示用)

$status = UserBanService::getBanStatus($uid);
// 返回 ['ban_type', 'ban_reason', 'ban_time', 'banned_until',
//       'expire_formatted', 'status_label', 'status_color']

status_color 用于 Bootstrap 徽章:success(正常)/ warning(禁言)/ danger(禁止访问)/ dark(锁定)。

辅助方法

UserBanService::getBanTypeLabel($banType);   // 返回 ['label'=>..., 'color'=>...]
UserBanService::formatDuration($duration);    // "7天" / "永久" / "3小时"
UserBanService::formatExpireTime($banned_until); // "2026-07-09 12:00:00" / "永久"

5. 模型函数

5.1 ban_log.func.php(封禁历史)

ban_log_create($data)                         // 创建记录(自动补 create_time)
ban_log_find_by_uid($uid, $page=1, $ps=20)    // 按 uid 查询
ban_log_count_by_uid($uid)                    // 按 uid 计数
ban_log_find_all($cond=[], $page=1, $ps=50)   // 后台查询所有
ban_log_delete_by_uid($uid)                   // 删除某用户所有记录(用户被彻底删除时调用)
ban_log_find_recent_unbanned($days=30, $lim=20) // 近 N 天解封记录(公示页用)

5.2 banned_ip.func.php(IP 黑名单)

banned_ip_create($ip_start, $ip_end, $reason, $admin_uid, $expire_time=0) // 创建
banned_ip_delete($id)                    // 删除
banned_ip_find($page=1, $pagesize=50)    // 列表
banned_ip_count()                        // 计数
banned_ip_check($ip)                     // 检查 IP 是否命中(已废弃,转发到 IpBlacklistService::is_blacklisted())
banned_ip_read($id)                      // 单条查询

新代码请直接用 IpBlacklistService::is_blacklisted($ip)(位于 lib/security/IpBlacklistService.php),banned_ip_check() 仅保留兼容。

6. 后台管理

6.1 用户管理扩展(admin/route/user.php

Action

用途

list

用户列表,支持按 ban_type 筛选,显示状态徽章、批量操作 Modal、行内一键禁言7天按钮

update

用户编辑页含「封禁设置」区(类型/时长/原因),已封禁显示当前状态并支持修改

ban

POST 封禁(POST 处理在 header include 之前)

unban

POST 解封

clear_content

POST 清空内容

ban_log

查看某用户封禁历史

6.2 IP 黑名单(admin/route/banned_ip.php

后台菜单「其他 → IP 黑名单」,支持单 IP / IP 段新增、过期时间设置、删除。

6.3 升级

部署后必须到 /admin/?upgrade.htm 执行「用户封禁系统」升级项,会:

  1. 为 user 表添加 4 个新字段

  2. 创建 bbs_user_ban_log 表

  3. 创建 bbs_banned_ip 表

  4. 为已存在用户初始化 ban_type=0

7. 核心检查点

入口

文件

检查内容

全局

index.inc.php

ban_type=2,3 跳转封禁提示页(admin 豁免用 SCRIPT_NAME,管理员组豁免,AJAX 返回 JSON)

登录

route/user.php login

ban_type=2,3 拒绝登录 + IP 黑名单

注册

route/user.php create

IP 黑名单

找密

route/user.php resetpw

ban_type=3 锁定拒绝

改密

route/my.php password

ban_type=3 锁定拒绝(改密在 my.php 不在 user.php)

发主题

route/thread.php create

ban_type>0 拒绝 + IP 黑名单

发回帖

route/post.php create

ban_type>0 拒绝

编辑

route/post.php update

ban_type>0 拒绝

封禁提示页view/htm/banned_notice.htm 显示封禁原因、解封时间、倒计时、申诉链接、退出登录按钮。

8. 前台内容显示

被封用户发布的内容会被隐藏,显示占位提示「该用户被关禁闭,内容被隐藏」。涉及的模板:

模板

处理

view/htm/thread_main.inc.htm

楼主主题内容隐藏 + 状态徽章 + 封禁按钮(版主/管理员可见)

view/htm/post_list.inc.htm

回帖内容隐藏 + 状态徽章 + 封禁按钮

view/htm/thread_list.inc.htm

帖子标题前 [已隐藏] 标记

view/htm/user_info_card.inc.htm

用户主页状态徽章 + 本人显示完整封禁信息 + 清空内容提示

复用函数model/misc.func.php):

  • user_ban_badge_html($banType) — 输出状态徽章 HTML

  • user_ban_hidden_notice_html() — 输出占位提示 HTML

特殊规则

  • 管理员(gid=1,2)可见被封用户原始内容

  • 被封用户本人可见自己的内容

  • 解封后内容自动恢复显示(unban() 只重置字段,不删内容)

  • 清空内容后用户主页显示「该用户已被管理员清空内容」提示

9. 封禁公示页

  • 路由:/bannedroute/banned.php

  • 模板:view/htm/banned.htm,双栏布局(当前封禁中 / 近期释放30天)

  • ban_show_public_list 配置控制,关闭时返回 404

  • 预留 hook 点:banned_list_display.php + XnEvent::trigger('UserBanService.bannedListDisplay')

10. 版主封禁入口

  • 路由:route/mod.php ban_user action

  • 权限:管理员(gid=1,2)直接放行;版主需 forum_access_mod($fid, $gid, 'allowbanuser')

  • 版主权限限制(三重校验)

    1. ban_type 必须为 1(禁言)

    2. duration 不能为 0(不能永久)

    3. duration 必须在 [86400, 604800](1-7天)

  • 管理员可永久封禁和锁定

  • 前台帖子页作者卡片「封禁」按钮(thread_main.inc.htm + post_list.inc.htm)+ 封禁弹窗 Modal

  • 路由 URL:mod_ban_user_url()model/route.func.php

11. xnx_report 举报系统联动

lib/security/ReportService.phphandle_report() / batch_handle() 中:

  • ban 分支:调用 UserBanService::ban($target_uid, BAN_TYPE_SILENCE, 604800, $reason, $handler_uid) 默认禁言 7 天

  • delete_ban 分支:先删内容再封禁(封禁失败时保持已处理状态,提示「内容已删除,但封禁失败」)

  • 封禁失败回滚:纯 ban 操作失败时回滚举报状态为待处理

  • 复用现有「封禁用户」「删除并封禁」按钮 UI,不新增重复按钮

12. 插件扩展接口

12.1 XnEvent 事件机制

文件位置:lib/XnEvent.php,提供 on / once / trigger / off / hasListeners 五个静态方法。

事件名约定ClassName.methodName,如 UserBanService.beforeBan

回调签名function(&$args)(参数按引用传递,可修改后传递给主流程)。

异常处理:回调抛出异常不会中断主流程,仅记录 xn_log('error')

12.2 UserBanService 触发的 7 个事件

事件名

触发时机

可修改参数

UserBanService.beforeBan

封禁前

banType / duration / reason(引用,可修改)

UserBanService.afterBan

封禁后

只读,含 bannedUntil

UserBanService.beforeUnban

解封前

reason(引用,可修改)

UserBanService.afterUnban

解封后

只读

UserBanService.beforeClearContent

清空前

uid / adminUid

UserBanService.afterClearContent

清空后

只读

UserBanService.bannedListDisplay

公示页渲染时

current_list / recent_list(引用,可修改)

12.3 PHP hook 点

Hook 文件

位置

用途

user_ban_check.php

route/user.php / route/thread.php / route/post.php / route/my.php / index.inc.php

自定义封禁检查(如第三方风控插件判定)

banned_ip_check.php

route/user.php login/create / route/thread.php create

自定义 IP 检查(如外接 IP 信誉库)

banned_list_display.php

route/banned.php

修改封禁公示页列表数据

12.4 插件调用示例

示例 1:监听封禁事件,记录到第三方日志系统

// plugin/my_audit/hook/model_inc_start.php
<?php exit;
if(!class_exists('UserBanService')) { include_once APP_PATH.'lib/UserBanService.php'; }

XnEvent::on('UserBanService.afterBan', 'my_audit', function(&$args) {
    // $args 含 uid/banType/duration/reason/adminUid/bannedUntil
    // 写入第三方审计系统(如 Elasticsearch)
    my_audit_log_write('user_ban', array(
        'uid'        => $args['uid'],
        'ban_type'   => $args['banType'],
        'duration'   => $args['duration'],
        'reason'     => $args['reason'],
        'admin_uid'  => $args['adminUid'],
        'expire_at'  => $args['bannedUntil'],
    ));
});

示例 2:封禁前修改封禁时长(如风控插件自动延长)

// plugin/risk_control/hook/model_inc_start.php
<?php exit;
XnEvent::on('UserBanService.beforeBan', 'risk_control', function(&$args) {
    // 检查用户风险等级
    $risk = RiskControlService::getRiskLevel($args['uid']);
    if($risk === 'high' && $args['duration'] > 0 && $args['duration'] < 86400 * 30) {
        // 高风险用户:自动延长到 30 天
        $args['duration'] = 86400 * 30;
        $args['reason'] .= '(风控自动延长至30天)';
    }
});

示例 3:插件中调用 UserBanService 封禁用户

// plugin/my_plugin/route/my_plugin.php
<?php
!defined('DEBUG') AND exit('Access Denied');

// 必须先 include_once(生产环境 min.php 类加载顺序不可预测)
if(!class_exists('UserBanService')) {
    include_once APP_PATH.'lib/UserBanService.php';
}

if($method == 'POST' && $action == 'auto_ban') {
    CsrfService::check();

    $target_uid = intval(param('uid'));
    $reason = param('reason', '', FALSE);  // 第3参数 FALSE 关闭 htmlspecialchars

    // 调用核心封禁服务(禁言 3 天)
    $result = UserBanService::ban(
        $target_uid,
        UserBanService::BAN_TYPE_SILENCE,
        86400 * 3,
        $reason,
        $uid   // 当前登录管理员 uid
    );

    if($result['code'] != 0) {
        message(-1, $result['message']);
    }
    message(0, lang('user_ban_success'));
}

示例 4:解封时清理插件自身数据

// plugin/my_plugin/hook/model_inc_start.php
<?php exit;
XnEvent::on('UserBanService.afterUnban', 'my_plugin', function(&$args) {
    // 清理插件中存储的该用户封禁期间数据
    db_delete('my_plugin_ban_data', array('uid' => $args['uid']));
});

示例 5:自定义 IP 检查(外接 IP 信誉库)

// plugin/ip_reputation/hook/banned_ip_check.php
<?php exit;
// 此 hook 在 banned_ip_check($ip) 落地后调用
// 如需更严格的检查,可直接调用 IpBlacklistService::is_blacklisted($ip) 或自建查询
$reputation = IpReputationService::query($ip);
if($reputation['score'] < -50) {
    // 自动加入本地黑名单
    if(!class_exists('IpBlacklistService')) {
        include_once APP_PATH.'lib/security/IpBlacklistService.php';
    }
    IpBlacklistService::add($ip, $ip, 'IP信誉库自动拦截', 0, 86400 * 7);
    message(-1, lang('user_ban_ip_banned'));
}

示例 6:修改封禁公示页列表

// plugin/my_plugin/hook/model_inc_start.php
<?php exit;
XnEvent::on('UserBanService.bannedListDisplay', 'my_plugin', function(&$args) {
    // $args['current_list'] / $args['recent_list'] 是引用
    // 添加插件标识的徽章
    foreach($args['current_list'] as &$row) {
        $row['plugin_badge'] = '⚠️';
    }
});

12.5 插件卸载时清理事件监听器

// plugin/my_plugin/uninstall.php
<?php
!defined('DEBUG') AND exit('Access Denied');
if(!class_exists('XnEvent')) {
    include_once APP_PATH.'lib/XnEvent.php';
}
// 移除本插件注册的所有事件监听器
XnEvent::off(null, 'my_plugin');

13. 多语言包

封禁系统涉及的语言包 key(zh-cn / zh-tw / en-us 三语已同步):

  • 前台lang/{lang}/bbs_common.php,约 61 个 user_ban_* key):状态标签、拒绝消息、通知文案、时长格式

  • 后台lang/{lang}/bbs_admin.php,约 88 个 admin_user_ban_* / admin_banned_ip_* key):表单标签、按钮文案、提示信息

带占位符的 key

  • user_ban_notice_ban — 含 {type} {reason} {duration} {expire}

  • user_ban_duration_minutes / user_ban_duration_hours / user_ban_duration_days — 含 {n}

新增功能时必须同步三种语言包,否则用户看到原始 key 名。

14. 安全规范

  • 所有 POST 表单包含 CsrfService::input() + 后端 CsrfService::check()

  • 后台路由 POST 处理在 header.inc.htm include 之前(message() 303 要求)

  • IP 字段写入用 ip2long() 转整型,禁用 intval("ip字符串")(只返回第一段)

  • IP / 原因等参数 param() 第 3 参数传 FALSE 关闭 htmlspecialchars

  • ban_type 等字段不在 USER_UPDATE_PROTECTED_FIELDS 中,用 user_update() 而非 user__update()(前者自动 cache_delete + 触发 hook)

  • 删除操作幂等:对已删除记录返回成功而非 404

  • admin 检测用 SCRIPT_NAME(兼容子目录安装),非 REQUEST_URI

15. 缓存与编译同步

  • XnEvent.php 已同步到 xiunophp/xiunophp.min.php

  • 修改 xiunophp/xiunophp.php 后必须运行 bash scripts/check_min_sync.sh(退出码 0 才算通过)

  • 修改模板/PHP 后清理 tmp/ 缓存

16. 关键文件清单

类型

文件

核心服务

lib/UserBanService.php

事件机制

lib/XnEvent.php

升级服务

lib/UpgradeService.phpupgradeUserBanSystem() 方法)

模型

model/ban_log.func.phpmodel/banned_ip.func.php

IP 黑名单服务

lib/security/IpBlacklistService.php

全局检查

index.inc.php

路由检查

route/user.phproute/thread.phproute/post.phproute/my.php

封禁提示页

view/htm/banned_notice.htm

公示页

route/banned.phpview/htm/banned.htm

版主入口

route/mod.phpban_user action)

后台用户管理

admin/route/user.phpadmin/view/htm/user_list.htmuser_update.htmuser_ban_log.htm

后台 IP 黑名单

admin/route/banned_ip.phpadmin/view/htm/banned_ip_list.htm

举报联动

lib/security/ReportService.php

复用函数

model/misc.func.phpuser_ban_badge_html / user_ban_hidden_notice_html

数据库

install/install.sql

配置

conf/conf.default.php

17. 测试要点

部署后建议测试以下场景:

  1. 基础封禁:后台编辑用户 → 选择禁言 7 天 → 提交 → 用户登录前台发帖被拒

  2. 场景隔离:禁言用户可登录浏览,但发帖/回帖/编辑被拒;禁止访问用户登录被拒

  3. 自动解封:设置封禁时长 1 分钟 → 等待过期 → 再次访问 → 自动解封

  4. 永久封禁:duration=0 → banned_until=9999999999 → 永不解封

  5. 管理员豁免:尝试封禁 gid=1,2 用户 → 拒绝;管理员自己访问被封 IP 不受影响

  6. 不能封禁自己:管理员尝试封禁自己 → 拒绝

  7. 版主权限:版主尝试永久封禁 → 拒绝;尝试禁言 8 天 → 拒绝;尝试禁止访问 → 拒绝

  8. 内容隐藏:被封用户发的帖子,普通用户看到占位提示,管理员看到原始内容

  9. 解封恢复:解封后帖子内容自动恢复显示

  10. 清空内容:清空操作 → 该用户主页显示「已被管理员清空内容」

  11. IP 黑名单:添加 IP → 用该 IP 访问 → 登录/注册/发帖三个入口全部被拒

  12. 封禁公示页:开启 ban_show_public_list → 访问 /banned 看到双栏列表

  13. 封禁历史:多次封禁解封后,后台 user-ban_log-{uid}.htm 显示完整历史

  14. xnx_report 联动:举报 → 选择「封禁用户」→ 用户被禁言 7 天 + 通知

  15. 生产环境:DEBUG=0 模式下访问各入口,确认 UserBanService 类加载正常(无 Class not found)

最新回复

请先登录后再回复 登录

uid:1 管理
关注
随遇而安,随缘而行
发帖 44
评论 236
粉丝 9
关注 1
发新帖
目录

扫码手机打开本帖