aiogram中如何将用户ID作为参数传入装饰器以实现命令权限校验
aiogram中如何将用户ID作为参数传入装饰器以实现命令权限校验
你的问题我太懂了——刚开始用aiogram写权限校验的时候,很容易踩这个装饰器执行时机的坑!你之前的写法之所以报错,是因为装饰器是在函数定义阶段就执行的,这时候message对象还根本没生成呢,自然会提示“未引用”。
不用搞复杂的类或者会话,咱们稍微调整一下装饰器的写法就能解决,核心思路是:把获取用户ID的逻辑移到装饰器内部的包装函数(wrapper)里,因为wrapper是在用户触发命令、bot实际处理请求的时候才运行的,这时候message已经存在了。
给你改好的代码,直接能用:
首先定义权限校验的装饰器:
from functools import wraps from aiogram import types # 管理员ID列表,保持你原来的配置 admins = [123123, 12312] def is_authorized(func): @wraps(func) async def wrapper(*args, **kwargs): # 从函数参数里找到Message对象——aiogram的命令处理函数第一个参数一般就是它 message = args[0] if args else kwargs.get('message') if not message: return # 极端情况没拿到message就直接返回 user_id = message.from_user.id if user_id in admins: # 有权限,执行原函数 return await func(*args, **kwargs) else: # 没权限的话可以给用户个提示(可选) await message.reply("抱歉,你没有执行这个命令的权限") return return wrapper
然后用这个装饰器的时候,直接加在命令装饰器下面就行,不用传任何参数:
@dp.message(Command(commands=["log"])) @is_authorized # 这里不用传message.from_user.id了! async def loglast20(message: types.Message): await message.reply('some logs here')
如果担心你的处理函数参数顺序或者命名不一样,还可以把获取message的逻辑写得更鲁棒一点,自动识别参数里的types.Message对象:
def is_authorized(func): @wraps(func) async def wrapper(*args, **kwargs): message = None # 先遍历位置参数找Message对象 for arg in args: if isinstance(arg, types.Message): message = arg break # 位置参数里没找到就看关键字参数 if not message: message = kwargs.get('message') if not message: return user_id = message.from_user.id if user_id in admins: return await func(*args, **kwargs) else: await message.reply("抱歉,你没有执行这个命令的权限") return return wrapper
这样不管你的处理函数怎么定义参数,都能准确拿到用户的ID做校验啦,完全符合你想要的“简单”需求。
备注:内容来源于stack exchange,提问作者reeqo
相关产品推荐
相关产品推荐

