discord.py中使用@commands.has_role无法限制机器人命令权限的问题
为什么@commands.has_role()在on_message事件里失效?
问题出在你用错了装饰器的适用场景——@commands.has_role()这类权限装饰器是discord.py专门为**命令框架(Command Framework)**设计的,也就是那些用@client.command()装饰的命令函数,它根本不会对on_message这种事件监听函数生效。
当你把它加在on_message上时,discord.py完全不会执行这个装饰器里的权限检查逻辑,自然不管用户有没有xrole,只要发了!set就能触发命令。
两种解决办法
方法1:改用discord.py命令框架(推荐)
这是最规范的写法,discord.py会帮你处理权限检查、参数解析、错误提示等一堆杂事,代码更简洁可靠:
@client.command() @commands.has_role('xrole') # 这里的装饰器会正常生效! async def set(ctx, user_name: str, credit_add_amount: int): # 直接用框架解析好的参数,不用自己split了 db[user_name] = credit_add_amount await ctx.send(f"{user_name} has been set with {credit_add_amount}. For further credit adjustment use !add")
- 这里用户输入
!set 用户名 100时,框架会自动把用户名和100解析成函数参数,还会自动检查参数类型(比如credit_add_amount必须是整数,否则会给用户发错误提示)。 - 如果用户没有
xrole,框架会自动返回权限不足的提示,不用你手动写逻辑。
方法2:坚持用on_message?手动检查角色
如果你一定要用on_message来监听命令,那就得自己手动实现角色检查逻辑:
@client.event async def on_message(message): # 别忘了加这句,不然命令框架的其他命令会失效(如果有的话) await client.process_commands(message) if message.content.startswith("!set"): # 手动遍历用户的所有角色,检查是否存在xrole has_permission = any(role.name == 'xrole' for role in message.author.roles) if not has_permission: await message.channel.send("你没有执行这个命令的权限!") return # 处理参数(记得加异常判断,防止用户输入错误) credits_message = message.content.split(" ", 2) if len(credits_message) < 3: await message.channel.send("用法错误!请输入:!set <用户名> <积分数量>") return user_name = credits_message[1] try: credit_add_amount = int(credits_message[2]) except ValueError: await message.channel.send("积分数量必须是整数哦!") return db[user_name] = credit_add_amount await message.channel.send(f"{user_name} has been set with {credit_add_amount}. For further credit adjustment use !add")
- 注意:用角色名称检查可能会有大小写问题,比如服务器里的角色是
XRole而不是xrole,就会检查失败。更可靠的方式是用角色ID检查:把role.name == 'xrole'改成role.id == 123456789012345678(换成你实际的角色ID)。
内容的提问来源于stack exchange,提问作者Yuvanesh Anand
相关产品推荐
相关产品推荐

