【问题标题】:Ejabberd - get user from multi user chat message using Smack XMPP client or enforce nicknameEjabberd - 使用 Smack XMPP 客户端从多用户聊天消息中获取用户或强制昵称
【发布时间】:2023-01-31 22:28:54
【问题描述】:

我正在运行一个带有一系列锁定多用户聊天的 ejabberd 服务器(仅限会员,需要注册,不允许更改主题或 PM 等) 一个要求是严格识别每个房间中有哪些用户(在向服务器注册时根据他们的用户 ID/帐户 Jid),以及哪个用户发送了消息。

这是如何实现的并不重要,它可以是: a) 通过从 message.getFrom() 获取 userId b) 通过从消息发件人处获取昵称/资源部分,并强制用户可以选择的昵称

在直接消息中,发件人的 JID 将如下所示:

<用户 ID>@<域>/<资源部分>

所以我可以使用 userId (LocalPart) 而不必太担心选择的昵称。

然而,这在多用户聊天中是不可能的,因为 Jid 将显示为:

<roomName>@conference.<domain>/<resourcepart>

发件人的 userId 不存在,所以我必须依赖昵称,但这可以由用户设置为任何内容(并在聊天中随时更改)

有没有办法强制设置昵称? (即设置为与 userId 相同的值)或以其他方式从多用户聊天消息中提取 userId?

【问题讨论】:

  • 当您实际上想使用非匿名房间时,您似乎使用了伪匿名房间。可以配置每个房间的设置。
  • 我们已经在 ejabberd.yml 中设置了 default_room_options: anonymous: false,但是 smack 客户端仍然只能将 JID 查看为 &lt;roomname&gt;@conference.&lt;domain&gt;/&lt;resourcepart&gt;。我错过了什么吗?

标签: xmpp ejabberd smack multiuserchat


【解决方案1】:

正如我所写,您需要一个非匿名房间。房间居住者的真实 XMPP 地址 (JID) 将成为参与者存在的一部分 (XEP-0045 § 7.2.3)。您可以通过MultiUserChat.getOccupantPresence​(EntityFullJid user) 获取居住者的存在。从这个Presence你想通过MUCUser.from(presence)额外的MUCUser信息。您可以从中额外添加 MUCIitem,它应该允许通过 MUCItem.getJid() 检索真实的 JID1个.

1:请注意,如果此方法似乎具有误导性,则 javadoc 应包含用户的真实 JID 而不是 MUC JID。

【讨论】:

  • 如果我尝试调用此方法,我会收到“方法 getOc​​cupantPresence (EntityFullJid) 未定义类型 MultiUserChat”。使用 Smack v4.4.6
  • 好的,上面的错误是由 Eclipse 中的一个故障引起的。它现在运行良好,是我一直在寻找的解决方案
  • 实际上,这种方法似乎只有在用户仍在房间内时才有效。如果用户发送一条消息然后离开,那么连接以检索历史消息的客户端将无法通过这种方式查找真实的 JID,因为该状态不再可用
【解决方案2】:

有一个房间选项允许所有房间住户查看其他住户的真实 Jabber ID。默认情况下,只有房间管理员可以查看那些真实的 Jabber ID。

另一种方法是自定义源代码,仅在昵称与 JID 中的用户名相同时才接受房间加入,并且之后不接受任何昵称更改。

【讨论】:

  • 第一个选项更可取,但我认为那是 default_room_options: anonymous: false 应该实现的目标?有趣的是,正在连接的管理员帐户(也使用 smack 客户端)有同样的问题——只能将 JID 查看为&lt;roomname&gt;@conference.&lt;domain&gt;/&lt;resourcepart&gt;
【解决方案3】:

Flow 上面给出的答案适用于仍在房间里的用户。但是,对于用户离开房间的历史消息,Presence 将不可用。

对于没有 Presence 的用户,消息节将包含一个地址节点,例如:

<message 
    xmlns='jabber:client' 
    xml:lang='en' 
    to='bob@example.com/12345'
    from='dummyroom@conference.example.com/johnny' 
    id='purple44d872cb' type='groupchat'>
    <addresses xmlns='http://jabber.org/protocol/address'>
        <address xmlns='http://jabber.org/protocol/address' type='ofrom' jid='john@example.com/12345'/>
    </addresses>
    <delay xmlns='urn:xmpp:delay' stamp='2023-01-27T10:08:59.594+00:00' from='dummyroom@conference.example.com'/>
    <body>me</body>
</message>

为了在 smack 中提取它,我调用了消息 toXML() 方法来获取节,然后使用 XML 解析器提取 jid 属性,即:

import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.impl.JidCreate;

public static EntityFullJid getUserJIDFromMessage(MultiUserChat muc, Message message) {
    EntityFullJid jid = null;
    
    //1. Extract JID from presence
    try {
        EntityFullJid channelJid = JidCreate.entityFullFrom(message.getFrom());
        jid = extractJidFromPresence(muc, channelJid);
        if (jid != null) return jid;
    } catch (Exception e) {}
    
    //2. If presence unavailable, parse the stanza
    Document messageDoc = Jsoup.parse(message.toXML().toString());
    for (Element address: messageDoc.select("addresses").select("address")) {
        if (address.attr("type").equals("ofrom")) {
            try {
                jid = JidCreate.entityFullFrom(address.attr("jid"));
                return jid;
            } catch (Exception e) {}
        }
    } return null;
}

private static EntityFullJid extractJidFromPresence(MultiUserChat muc, EntityFullJid channelJid) {
    EntityFullJid jid = null;
    try {
        MUCUser mucUser = MUCUser.from(muc.getOccupantPresence(channelJid));
        jid = (EntityFullJid) mucUser.getItem().getJid();
        return jid;
    } catch (Exception e) {}
    return jid;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 2014-04-16
    • 1970-01-01
    相关资源
    最近更新 更多