Ejabberd群聊中如何通过Smack获取用户ID或强制昵称与用户ID一致?
针对你在严格限制的MUC场景下需要准确识别消息发送者真实JID的需求,这里有几个可行的方案,结合Ejabberd的配置和扩展能力来实现:
方案1:强制MUC昵称与用户LocalPart(userId)一致并禁止修改
这是最直接的方式,从源头固定用户在MUC中的标识,避免昵称随意修改带来的识别问题。
你可以通过修改Ejabberd的mod_muc配置来实现:
- 启用
nickname_required,确保用户进入房间必须设置昵称; - 设置
force_nick为local,强制用户使用自己JID的LocalPart(也就是你的userId)作为昵称; - 开启
restrict_nick_changes,禁止用户在进入房间后修改昵称。
对应的配置片段大概是这样的:
modules: mod_muc: hosts: ["conference.@HOST@"] nickname_required: true force_nick: local restrict_nick_changes: true
这样用户进入房间时,会自动使用自己的userId作为昵称,而且无法修改,你就可以直接从MUC消息的from字段的资源部分提取到真实的userId了。
方案2:让MUC消息携带发送者的真实JID
如果不想限制用户的昵称,你可以配置Ejabberd让MUC在转发消息时,附带发送者的真实JID信息。
Ejabberd的mod_muc支持在房间配置中开启send_real_jid选项,这样当用户发送消息时,MUC会在消息的XML扩展部分(符合XEP-0045规范)添加发送者的真实JID。
你可以在全局mod_muc配置里设置,或者针对单个房间配置:
modules: mod_muc: hosts: ["conference.@HOST@"] rooms: "strict_room@conference.@HOST@": send_real_jid: true # 你的其他严格限制配置: members_only: true allow_change_subject: false allow_private_messages: false
这样接收方收到的MUC消息里,会包含类似下面的XML元素:
<x xmlns="http://jabber.org/protocol/muc#user"> <item jid="user1@yourdomain.com/resource" affiliation="member" role="participant"/> </x>
你可以解析这个jid属性来获取用户的真实LocalPart(userId)。
方案3:自定义钩子注入真实JID(进阶)
如果上面的配置满足不了需求,你可以利用Ejabberd的钩子系统,编写一个简单的自定义模块来处理MUC消息,在消息中注入发送者的真实JID。
比如写一个Elixir模块,监听muc_filter_message钩子,然后在消息中添加一个自定义的XML元素:
defmodule ModMucInjectRealJid do @behaviour :gen_mod def start(_host, _opts) do :ejabberd_hooks.add(:muc_filter_message, _host, __MODULE__, :inject_real_jid, 50) end def stop(_host) do :ejabberd_hooks.delete(:muc_filter_message, _host, __MODULE__, :inject_real_jid, 50) end def inject_real_jid(message, room_jid, from_jid, _opts) do # 从from_jid获取真实用户JID real_jid = :jid.to_string(from_jid) # 创建自定义XML元素 real_jid_element = {:xmlel, "real_jid", [], [{:xmlcdata, real_jid}]} # 添加到消息的扩展部分 updated_message = :xmlel.add_child(message, real_jid_element) updated_message end end
然后在Ejabberd配置中启用这个模块:
modules: ModMucInjectRealJid: {}
这样接收方就能从消息的real_jid元素中直接获取到发送者的真实JID,进而提取userId。
内容的提问来源于stack exchange,提问作者nick_j_white

