Skip to main content
Version: 2.3.3

权限控制

权限控制是机器人在实际应用中需要解决的重点问题之一,NoneBot 提供了灵活的权限控制机制 —— Permission

类似于响应规则 RulePermission 是由非负整数个 PermissionChecker 所共同组成的用于筛选事件的对象。但需要特别说明的是,权限和响应规则有如下区别:

  1. 权限检查先于响应规则检查
  2. Permission 只需其中一个 PermissionChecker 返回 True 时就会检查通过
  3. 权限检查进行时,上下文中并不存在会话状态 state
  4. Rule 仅在初次触发事件响应器时进行检查,在余下的会话中并不会限制事件;而 Permission持续生效,在连续对话中一直对事件主体加以限制。

基础使用

通常情况下,Permission 更侧重于对于触发事件的机器人用户的筛选,例如由 NoneBot 自身提供的 SUPERUSER 权限,便是筛选出会话发起者是否为超级用户。它可以对输入的用户进行鉴别,如果符合要求则会被认为通过并返回 True,反之则返回 False

简单来说,Permission 是一个用于筛选出符合要求的用户的机制,可以通过 Permission 精确的控制响应对象的覆盖范围,从而拒绝掉我们所不希望的事件。

例如,我们可以在 weather 插件中添加一个超级用户可用的指令:

from typing import Tuple
from nonebot.permission import SUPERUSER

manage = on_command(
("天气", "启用"),
rule=to_me(),
aliases={("天气", "禁用")},
permission=SUPERUSER,
)

@manage.handle()
async def control(cmd: Tuple[str, str] = Command()):
_, action = cmd
if action == "启用":
plugin_config.weather_plugin_enabled = True
elif action == "禁用":
plugin_config.weather_plugin_enabled = False
await manage.finish(f"天气插件已{action}")

如上方示例所示,在注册事件响应器时,我们设置了 permission 参数,那么这个事件处理器在触发事件前的检查阶段会对用户身份进行验证,如果不符合我们设置的条件(此处即为超级用户)则不会响应。此时,我们向机器人发送 /天气.禁用 指令,机器人不会有任何响应,因为我们还不是机器人的超级管理员。我们在 dotenv 文件中设置了 SUPERUSERS 配置项之后,机器人就会响应我们的指令了。

SUPERUSERS=["console_user"]
NoneBot
/天气.禁用
天气插件已禁用
/天气.启用
天气插件已启用

自定义权限

与事件响应规则类似,PermissionChecker 也是一个返回值为 bool 类型的依赖函数,即 PermissionChecker 支持依赖注入。例如,我们可以限制用户的指令调用次数:

from nonebot.adapters import Event

fake_db: Dict[str, int] = {}

async def limit_permission(event: Event):
count = fake_db.setdefault(event.get_user_id(), 100)
if count > 0:
fake_db[event.get_user_id()] -= 1
return True
return False

weather = on_command("天气", permission=limit_permission)

权限组合

权限之间可以通过 | 运算符进行组合,使得任意一个权限检查返回 True 时通过。例如:

perm1 = Permission(foo_checker)
perm2 = Permission(bar_checker)

perm = perm1 | perm2
perm = perm1 | bar_checker
perm = foo_checker | perm2

同样的,我们也无需担心组合了一个 None 值,Permission 会自动忽略 None 值。

assert (perm | None) is perm

主动使用权限

除了在事件响应器中使用权限外,我们也可以主动使用权限来判断事件是否符合条件。例如:

perm = Permission(some_checker)

result: bool = await perm(bot, event)

我们只需要传入 Bot 实例、事件,Permission 会并发调用所有 PermissionChecker 进行检查,并返回结果。