Skip to content

权限与访问控制 ​

「这条指令谁能用」由命令管理器统一处理:ctx.command() 的 permission 字段在派发时直接执行,配置文件再提供按插件、群、用户的细粒度覆盖。

角色 ​

框架配置里有两份名单,写在项目 package.json 的 mioku 字段(见配置文件):

名单角色
owners主人(master),最高权限
admins管理员(admin),仅次于主人
(其他人)普通成员(member)

除了配置名单,群聊场景下还会识别发送者在群里的身份:

来源角色
mioku.ownersmaster
当前群群主owner(仅限所在群生效)
mioku.admins 或当前群管理员admin

这些角色映射到命令的 permission 字段:

值谁能触发
member所有人
adminbot 主人、配置管理员、当前群群主或群管理员
ownerbot 主人或当前群群主
master仅 bot 主人

推荐做法:把角色写在 ctx.command() 上,让命令管理器执行:

typescript
ctx.command({
  name: "weather",
  permission: "member",
  handler: async ({ event, args }) => {
    await event.reply(`查询 ${args.join(" ") || "当前城市"}`);
  },
});

ctx.command({
  name: "stats",
  permission: "admin", // 主人、管理员、群主或群管理员
  handler: async ({ event }) => {
    await event.reply("系统统计信息");
  },
});

ctx.command({
  name: "shutdown",
  permission: "master", // 仅主人
  handler: async () => { /* ... */ },
});

权限不满足时命令会被悄悄丢弃,handler 不会被调用,也不向用户报错(避免暴露命令存在)。需要主动提示时,可以在 handler 里调用 ctx.isMaster(event) / ctx.isOwner(event) 等判断。

ctx 上的判断方法 ​

ctx.isMaster(event) / ctx.isOwner(event) / ctx.isAdmin(event) 等方法与 permission 语义对齐,用于「非命令」分支(戳一戳回调、关键词命中后的二次判断、CD 豁免等):

方法返回 true 的条件等价 permission
ctx.isMaster(event)发送者在 mioku.owners 里(仅主人)master
ctx.isOwner(event)主人或当前群群主owner
ctx.isAdmin(event)主人、配置管理员、当前群群主或群管理员admin
ctx.isOwnerOrAdmin(event)同 isAdminadmin
ctx.hasRight(event)同 isAdminadmin

需要更细粒度判断时,可以用 ctx.isEventGroupOwner(event) / ctx.isEventGroupAdmin(event)(仅看当前群身份)、ctx.isEventAdminConfigOnly(event)(仅看 mioku.admins)、ctx.toUserId(event)(把事件压平为用户 id)。

框架会从事件里提取发送者 id(裸 id、user_id、sender.user_id 几种形态都认),再和名单比对,不同适配器的事件结构差异被它挡掉了。

访问控制:access-control ​

角色之外还有一层更细的控制:某个群就是不想让 music 插件响应,或者某条指令只想在特定人群开放。这类规则放在 config/core/access-control.json,core 插件第一次启动时会自动创建这个文件:

json
{
  "version": 1,
  "global": {
    "plugins": {
      "music": { "action": "block" }
    },
    "commands": {}
  },
  "groups": {
    "123456789": {
      "plugins": {
        "impact": { "action": "block" }
      },
      "commands": {
        "weather": {
          "上海天气": { "action": "allow" }
        }
      }
    }
  },
  "users": {
    "10001": {
      "commands": {
        "weather": {
          "查询": { "action": "block" }
        }
      }
    }
  }
}

结构解读:

字段说明
version固定为 1
global全局生效的规则
groups按群配置,键是群号字符串
users按用户配置,键是 QQ 号字符串

每个作用域里都是两级:plugins 按「插件名 → 规则」管整个插件,commands 按「插件名 → 命令 id → 规则」管具体命令。规则只有一个字段 action,取 allow(放行)或 block(拦截)。没配规则的命令一律放行——这份文件初始就是空的,默认行为是全部可用。

命令 id 是 ctx.command() 注册时的 id(默认等于 name),例如 weather、帮助菜单。这份文件可以手工编辑,也可以在 WebUI 的访问控制页面里改,效果一样。

优先级:用户 > 群 > 全局,同一作用域内 commands 优先于 plugins。bot 主人、管理员、群主、群管理员绕过访问规则,但不会绕过命令自身的 permission 角色限制。

内置 core 命令的权限 ​

core 插件的系统命令默认只有主人能触发:.plugin、.settings、.install、.uninstall、.restart、.log、.update、.exit 这些。例外是 .status(.状态)和 .adapter(.适配器),默认所有人可看;把 status_permission 配成 "admin-only" 后就需要主人或管理员。

.settings 值得一提:.settings add-owner / remove-owner / add-admin / remove-admin 会直接改写 package.json 里的 owners/admins 名单——它能「授权」别人,所以必须锁在主人手里。顺带一提,.settings remove-owner 不允许删第一主人。

core 命令同样能被 access-control 按 id 单独拦截,.plugin、settings、install、update 等命令都已被命令管理器登记。

参考 ​

Released under the MIT License with love.