扩展XMPP客户端的认证机制和消息类型
XMPP(Extensible Messaging and Presence Protocol,可扩展消息与存在协议)是目前主流的即时消息传输协议。
由于XMPP服务端的认证机制不同,需要XMPP客户端扩展对应的认证机制,否则无法接入XMPP服务器。
同样,XMPP服务端的接口会定义一些自定义的消息类型,用于支撑不同业务。这时,需要XMPP客户端同样支持扩展消息类型,否则无法识别消息,出现报错。
开源软件Smack是一款Java实现的XMPP客户端软件,下面分享如何在Smack的基础上扩展认证机制和扩展消息类型。
1、扩展认证机制
下面,我们以视频平台的XMPP服务端的认证接口定义为例,扩展Smack客户端的认证机制。
XMPP服务端认证接口定义(客户端的认证必须根据XMPP服务器的接口实现)如下:
请求消息定义:
参数名 | 参数类型 | 必选(M)/可选(O) | 参数说明 |
auth | 元素 | M | 用于承载授权机制的XMPP节。 |
auth/xmlns | 属性 | M | 默认为:urn:xmpp:sm:hw_ext |
auth/mechanism | 属性 | M | 鉴权算法,默认为:TOKEN |
auth/username | 元素 | M | 客户端JID。 |
auth/token | 元素 | M | 客户端token值,采用base64编码。 |
消息示例:
<auth xmlns='urn:xmpp:sm:hw_ext' mechanism='TOKEN'>
<username>user1@im.huawei.cn</username>
<token>YWJjZGVmJSYqNTY3ODk=</token>
</auth>
响应消息定义:
参数名 | 参数类型 | 必选(M)/可选(O) | 参数说明 |
success | 元素 | M | 表示鉴权成功。 |
success/xmlns | 属性 | M | 默认为:urn:xmpp:sm:hw_ext |
success/heartbeat | 属性 | O | 表示服务器希望客户端发送ping心跳的时间间隔,单位为秒。 不带本属性时,默认为:300秒 |
success/heartbeatTimes | 属性 | O | 心跳检测次数。 不带本属性时,默认为:5次 |
响应示例:
<success xmlns='urn:xmpp:sm:hw_ext ' heartbeat='300'/>
1.1定义认证消息类MyExtAuthMechanism
MyExtAuthMechanism继承SaslStreamElements.AuthMechanism类,重写public String getNamespace()和public XmlStringBuilder toXML(String enclosingNamespace)。
getNamespace方法返回消息的命名空间,例如上面定义“urn:xmpp:sm:hw_ext”。
toXML方法返回认证的xml消息,例如上面定义的消息示例。
1.2定义认证机制类MyExtSASLMechanism
MyExtSASLMechanism继承SASLMechanism类,重写public void authenticate(String host, DomainBareJid serviceName, CallbackHandler cbh, EntityBareJid authzid, SSLSession sslSession) throws SmackException, NotConnectedException, InterruptedException方法。
authenticate方法会向XMPP服务端发送认证消息,消息包装在MyExtAuthMechanism对象。
代码示例如下:
mechanism = "TOKEN";
authenticationText = "<username>user1@im.huawei.cn</username><token>YWJjZGVmJSYqNTY3ODk=</token>"
// connection是父类中的XMPPConnection对象,用于发送消息至XMPP服务器
connection.sendNonza(new MsaAuthMechanism(mechanism, authenticationText));
1.3增加认证响应消息处理
认证的响应消息中携带了心跳参数,Smack不支持处理认证响应中的参数,需要扩展认证成功消息处理步骤。
在smack-tcp模块的XMPPTCPConnection类中的parsePackets方法,增加对Success.ELEMENT消息的处理。例如提取响应中的心跳间隔时间。
1.4注册自定义认证机制
SASLAuthentication类提供了静态方法public static void registerSASLMechanism(SASLMechanism mechanism)用于注册一个新的认证方式;以MyExtSASLMechanism对象为参数,注册自定义认证机制。
1.5认证过程
XMPP客户端与服务端建立连接的过程如下:
认证过程包括10.Select an authentication mechanism和11.Send the authentication success response。
在Smack软件中,AbstractXMPPConnection类抽象了XMPP连接,XMPPTCPConnection是AbstractXMPPConnection子类,调用XMPPTCPConnection的connect方法与XMPP服务器建立通道连接,调用login方法进行登录认证。
login方法最终调用SASLAuthentication类中的authenticate方法,authenticate根据服务端支持的认证类型id选择对应的认证机制,例如上面定义的“TOKEN”,然后调用MyExtSASLMechanism的authenticate方法,将认证请求消息发送至服务端。详情可参考SASLAuthentication类中的authenticate方法。
2、扩展消息类型
下面,我们以支持视频平台的XMPP服务器的系统控制消息为例,扩展Smack客户端消息类型。
系统控制消息用于表示系统控制相关的命令,例如restart(重启)。
消息定义如下:
参数名 | 参数类型 | 必选(M)/可选(O) | 参数说明 |
message | 元素 | M | 用于承载即时消息的XMPP节。 |
message/type | 属性 | O | 消息类型,普通文本消息为:chat,控制消息为:sys-ctrl |
message/id | 属性 | M | 该即时消息的ID,由客户端自行生成。 |
message/from | 属性 | O | 消息发送方Full JID。 |
message/to | 属性 | M | 消息接收方Bare JID/Full JID |
message/body | 元素 | M | UTF-8编码的消息内容。 |
message/request | 元素 | O | 要求的报告类型,通过type属性携带。 |
message/request/xmlns | 属性 | M | 固定取值为:urn:xmpp:receipts |
message/request/type | 属性 | O | 发送方要求的报告的类型。 |
控制消息示例:
<message type='sys-ctrl' id='purplea7adefbc' from='111@im.huawei.cn/pushclient' to='222@im.huawei.cn'>
<body>restart</body>
<request xmlns='urn:xmpp:receipts'/>
</message>
消息类型定义在Smack core模块Message类中的Type内部类中,无法通过调用接口的方式扩展,只能通过修改Type类,增加新的消息类型。
例如在Type类中增加一个控制消息类型:
public enum Type {
// Default) a normal text message used in email like interface.
normal,
// pically short text message used in line-by-line chat interfaces.
chat,
// at message sent to a groupchat server for group chats.
groupchat,
// xt message to be displayed in scrolling marquee displays.
headline,
// ysctrl message sent to destination client for execute system command.
sysctrl,
// dicates a messaging error.
error;
}
需要注意的是,由于历史原因,上面XMPP消息类型sys-ctrl的定义中包含”-” 号,而Java变量中是不能包含”-” 号,因此上面定义的Type枚举值为sysctrl。
在解析、生成sys-ctrl消息时,需要对变量做sysctrl < -- > sys-ctrl转换,否则枚举值解析会报错。
同样,在定义接口中的消息类型时,也要考虑代码的实现。
2.1解析系统控制消息
当XMPP客户端收到服务端的消息时,会执行XMPPTCPConnection类中的parsePackets方法,根据消息的元素判断,如果是Message.ELEMENT消息,则调用parseAndProcessStanza方法解析消息内容。
parseAndProcessStanza方法最终会调用PacketParserUtils.parseMessage方法,parseMessage方法中根据Message.Type的枚举值解析消息类型,如果消息类型在Type中未定义,则出现消息解析失败错误。
public static Message parseMessage(XmlPullParser parser) hrows Exception {
……
if (typeString != null) {
// 根据Message Type枚举值来解析消息类型
message.setType(Message.Type.fromString(typeString));
}
3、XMPP应用场景
通过XMPP,可以实现VR头盔和大屏的同屏。
与DLNA不同,XMPP不受局域网限制,只要客户端与服务端网络连通,即可实现即时消息;
在360视频的同屏场景下,通过XMPP,VR头盔可以即时传送当前的角度至同屏机顶盒,机顶盒根据角度拉取符合大屏显示的分辨率的视频流,可以解决VR头盔视频分辨率与大屏分辨率不一致的问题。
- 点赞
- 收藏
- 关注作者
评论(0)