Files
Mofox-Core/src/plugin_system/apis/permission_api.py
雅诺狐 3edcc9d169 ruff
2025-12-08 15:48:40 +08:00

465 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
纯异步权限API定义。
这个模块提供了一套完整的权限管理系统,用于控制用户对各种功能的访问权限。
所有外部调用方必须使用 await 关键字因为这是异步API。
主要组件:
- PermissionLevel: 权限等级枚举
- PermissionNode: 权限节点数据类,描述单个权限项
- UserInfo: 用户信息数据类,标识用户身份
- IPermissionManager: 权限管理器抽象接口
- PermissionAPI: 对外暴露的权限API封装类
"""
from abc import ABC, abstractmethod # ABC: 抽象基类abstractmethod: 抽象方法装饰器
from dataclasses import dataclass # dataclass: 自动生成 __init__, __repr__ 等方法的装饰器
from enum import Enum # Enum: 枚举类型基类
from typing import Any # Any: 表示任意类型
from src.common.logger import get_logger
logger = get_logger(__name__) # 获取当前模块的日志记录器
class PermissionLevel(Enum):
"""
权限等级枚举类。
定义了系统中的权限等级,目前只有 MASTER管理员/主人)级别。
MASTER 用户拥有最高权限,可以执行所有操作。
"""
MASTER = "master" # 管理员/主人权限
@dataclass
class PermissionNode:
"""
权限节点数据类。
每个权限节点代表一个具体的权限项,例如"发送消息""管理用户"等。
属性:
node_name: 权限节点名称,例如 "plugin.chat.send_message"
description: 权限描述,用于向用户展示这个权限的用途
plugin_name: 注册这个权限的插件名称
default_granted: 是否默认授予所有用户False 表示需要显式授权
"""
node_name: str # 权限节点唯一标识名
description: str # 权限的人类可读描述
plugin_name: str # 所属插件名称
default_granted: bool = False # 默认是否授予(默认不授予)
@dataclass
class UserInfo:
"""
用户信息数据类。
用于唯一标识一个用户,通过平台+用户ID的组合确定用户身份。
属性:
platform: 用户所在平台,例如 "qq", "telegram", "discord"
user_id: 用户在该平台上的唯一标识ID
"""
platform: str # 平台标识,如 "qq", "telegram"
user_id: str # 用户ID
def __post_init__(self):
"""
dataclass 的后初始化钩子。
确保 user_id 始终是字符串类型,即使传入的是数字也会被转换。
这样可以避免类型不一致导致的比较问题。
"""
self.user_id = str(self.user_id)
class IPermissionManager(ABC):
"""
权限管理器抽象接口Interface
这是一个抽象基类,定义了权限管理器必须实现的所有方法。
具体的权限管理实现类需要继承此接口并实现所有抽象方法。
使用抽象接口的好处:
1. 解耦PermissionAPI 不需要知道具体的实现细节
2. 可测试:可以轻松创建 Mock 实现用于测试
3. 可替换:可以随时更换不同的权限管理实现
"""
@abstractmethod
async def check_permission(self, user: UserInfo, permission_node: str) -> bool:
"""
检查用户是否拥有指定权限。
Args:
user: 要检查的用户信息
permission_node: 权限节点名称
Returns:
bool: True 表示用户拥有该权限False 表示没有
"""
...
@abstractmethod
async def is_master(self, user: UserInfo) -> bool:
"""
检查用户是否是管理员/主人。
管理员拥有最高权限,通常绕过所有权限检查。
Args:
user: 要检查的用户信息
Returns:
bool: True 表示是管理员False 表示不是
"""
...
@abstractmethod
async def register_permission_node(self, node: PermissionNode) -> bool:
"""
注册一个新的权限节点。
插件在加载时会调用此方法注册自己需要的权限。
Args:
node: 要注册的权限节点信息
Returns:
bool: True 表示注册成功False 表示失败(可能是重复注册)
"""
...
@abstractmethod
async def grant_permission(self, user: UserInfo, permission_node: str) -> bool:
"""
授予用户指定权限。
Args:
user: 目标用户信息
permission_node: 要授予的权限节点名称
Returns:
bool: True 表示授权成功False 表示失败
"""
...
@abstractmethod
async def revoke_permission(self, user: UserInfo, permission_node: str) -> bool:
"""
撤销用户的指定权限。
Args:
user: 目标用户信息
permission_node: 要撤销的权限节点名称
Returns:
bool: True 表示撤销成功False 表示失败
"""
...
@abstractmethod
async def get_user_permissions(self, user: UserInfo) -> list[str]:
"""
获取用户拥有的所有权限列表。
Args:
user: 目标用户信息
Returns:
list[str]: 用户拥有的权限节点名称列表
"""
...
@abstractmethod
async def get_all_permission_nodes(self) -> list[PermissionNode]:
"""
获取系统中所有已注册的权限节点。
Returns:
list[PermissionNode]: 所有权限节点的列表
"""
...
@abstractmethod
async def get_plugin_permission_nodes(self, plugin_name: str) -> list[PermissionNode]:
"""
获取指定插件注册的所有权限节点。
Args:
plugin_name: 插件名称
Returns:
list[PermissionNode]: 该插件注册的权限节点列表
"""
...
class PermissionAPI:
"""
权限API封装类。
这是对外暴露的权限操作接口,插件和其他模块通过这个类来进行权限相关操作。
它封装了底层的 IPermissionManager提供更简洁的调用方式。
使用方式:
from src.plugin_system.apis.permission_api import permission_api
# 检查权限
has_perm = await permission_api.check_permission("qq", "12345", "chat.send")
# 检查是否是管理员
is_admin = await permission_api.is_master("qq", "12345")
设计模式:
这是一个单例模式的变体,模块级别的 permission_api 实例供全局使用。
"""
def __init__(self):
"""
初始化 PermissionAPI。
初始时权限管理器为 None需要在系统启动时通过 set_permission_manager 设置。
"""
self._permission_manager: IPermissionManager | None = None # 底层权限管理器实例
def set_permission_manager(self, manager: IPermissionManager):
"""
设置权限管理器实例。
这个方法应该在系统启动时被调用,注入具体的权限管理器实现。
Args:
manager: 实现了 IPermissionManager 接口的权限管理器实例
"""
self._permission_manager = manager
def _ensure_manager(self):
"""
确保权限管理器已设置(内部辅助方法)。
如果权限管理器未设置,抛出 RuntimeError 异常。
这是一个防御性编程措施,帮助开发者快速发现配置问题。
Raises:
RuntimeError: 当权限管理器未设置时
"""
if self._permission_manager is None:
raise RuntimeError("权限管理器未设置,请先调用 set_permission_manager")
async def check_permission(self, platform: str, user_id: str, permission_node: str) -> bool:
"""
检查用户是否拥有指定权限。
这是最常用的权限检查方法,在执行需要权限的操作前调用。
Args:
platform: 用户所在平台(如 "qq", "telegram"
user_id: 用户ID
permission_node: 要检查的权限节点名称
Returns:
bool: True 表示用户拥有权限False 表示没有
Example:
if await permission_api.check_permission("qq", "12345", "admin.ban_user"):
# 执行封禁操作
pass
"""
self._ensure_manager()
if not self._permission_manager:
return False
return await self._permission_manager.check_permission(UserInfo(platform, user_id), permission_node)
async def is_master(self, platform: str, user_id: str) -> bool:
"""
检查用户是否是管理员/主人。
管理员是系统的最高权限用户,通常在配置文件中指定。
Args:
platform: 用户所在平台
user_id: 用户ID
Returns:
bool: True 表示是管理员False 表示不是
"""
self._ensure_manager()
if not self._permission_manager:
return False
return await self._permission_manager.is_master(UserInfo(platform, user_id))
async def register_permission_node(
self,
node_name: str,
description: str,
plugin_name: str,
default_granted: bool = False,
*,
allow_relative: bool = True, # 仅关键字参数,目前未使用,预留给相对权限名功能
) -> bool:
"""
注册一个新的权限节点。
插件在初始化时应调用此方法注册自己需要的权限节点。
Args:
node_name: 权限节点名称,建议使用 "插件名.功能.操作" 的格式
description: 权限描述,向用户解释这个权限的作用
plugin_name: 注册此权限的插件名称
default_granted: 是否默认授予所有用户(默认 False需要显式授权
allow_relative: 预留参数,是否允许相对权限名(目前未使用)
Returns:
bool: True 表示注册成功False 表示失败
Example:
await permission_api.register_permission_node(
node_name="my_plugin.chat.send_image",
description="允许发送图片消息",
plugin_name="my_plugin",
default_granted=True # 所有用户默认都能发图片
)
"""
self._ensure_manager()
# 创建权限节点对象
node = PermissionNode(node_name, description, plugin_name, default_granted)
if not self._permission_manager:
return False
return await self._permission_manager.register_permission_node(node)
async def grant_permission(self, platform: str, user_id: str, permission_node: str) -> bool:
"""
授予用户指定权限。
通常由管理员调用,给某个用户赋予特定权限。
Args:
platform: 目标用户所在平台
user_id: 目标用户ID
permission_node: 要授予的权限节点名称
Returns:
bool: True 表示授权成功False 表示失败
Example:
# 授予用户管理权限
await permission_api.grant_permission("qq", "12345", "admin.manage_users")
"""
self._ensure_manager()
if not self._permission_manager:
return False
return await self._permission_manager.grant_permission(UserInfo(platform, user_id), permission_node)
async def revoke_permission(self, platform: str, user_id: str, permission_node: str) -> bool:
"""
撤销用户的指定权限。
通常由管理员调用,移除某个用户的特定权限。
Args:
platform: 目标用户所在平台
user_id: 目标用户ID
permission_node: 要撤销的权限节点名称
Returns:
bool: True 表示撤销成功False 表示失败
"""
self._ensure_manager()
if not self._permission_manager:
return False
return await self._permission_manager.revoke_permission(UserInfo(platform, user_id), permission_node)
async def get_user_permissions(self, platform: str, user_id: str) -> list[str]:
"""
获取用户拥有的所有权限列表。
可用于展示用户的权限信息,或进行批量权限检查。
Args:
platform: 目标用户所在平台
user_id: 目标用户ID
Returns:
list[str]: 用户拥有的所有权限节点名称列表
Example:
perms = await permission_api.get_user_permissions("qq", "12345")
print(f"用户拥有以下权限: {perms}")
"""
self._ensure_manager()
if not self._permission_manager:
return []
return await self._permission_manager.get_user_permissions(UserInfo(platform, user_id))
async def get_all_permission_nodes(self) -> list[dict[str, Any]]:
"""
获取系统中所有已注册的权限节点。
返回所有插件注册的权限节点信息,可用于权限管理界面展示。
Returns:
list[dict]: 权限节点信息列表,每个字典包含:
- node_name: 权限节点名称
- description: 权限描述
- plugin_name: 所属插件名称
- default_granted: 是否默认授予
Note:
返回字典而非 PermissionNode 对象便于序列化和API响应。
"""
self._ensure_manager()
if not self._permission_manager:
return []
nodes = await self._permission_manager.get_all_permission_nodes()
# 将 PermissionNode 对象转换为字典,便于序列化
return [
{
"node_name": n.node_name,
"description": n.description,
"plugin_name": n.plugin_name,
"default_granted": n.default_granted,
}
for n in nodes
]
async def get_plugin_permission_nodes(self, plugin_name: str) -> list[dict[str, Any]]:
"""
获取指定插件注册的所有权限节点。
用于查看某个特定插件定义了哪些权限。
Args:
plugin_name: 插件名称
Returns:
list[dict]: 该插件的权限节点信息列表,格式同 get_all_permission_nodes
"""
self._ensure_manager()
if not self._permission_manager:
return []
nodes = await self._permission_manager.get_plugin_permission_nodes(plugin_name)
# 将 PermissionNode 对象转换为字典
return [
{
"node_name": n.node_name,
"description": n.description,
"plugin_name": n.plugin_name,
"default_granted": n.default_granted,
}
for n in nodes
]
# ============================================================
# 模块级单例实例
# ============================================================
# 全局权限API实例供其他模块导入使用
# 使用方式: from src.plugin_system.apis.permission_api import permission_api
permission_api = PermissionAPI()