OpenFire源码学习之六:用户注册
用户注册
注册流程:
1、客户端进行握手给服务端发送连接消息:
<stream:stream to="192.168.2.104" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0"></stream:stream>
2、服务端回执:
<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="hytest240" id="9fd61155" xml:lang="en" version="1.0">
<stream:features>
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>DIGEST-MD5</mechanism>
<mechanism>JIVE-SHAREDSECRET</mechanism>
<mechanism>PLAIN</mechanism>
<mechanism>ANONYMOUS</mechanism>
<mechanism>CRAM-MD5</mechanism>
</mechanisms>
<compression xmlns="http://jabber.org/features/compress">
<method>zlib</method>
</compression><auth xmlns="http://jabber.org/features/iq-auth"/>
<register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>
3、客户端发送注册申请
<iq id="69Bxy-0" to="hytest240" type="get">
<query xmlns="jabber:iq:register"></query>
</iq>
4、服务端给出注册需要的填写的信息,相当与给客户端发送一个申请单
<iq type="result" id="69Bxy-0" from="hytest240">
<query xmlns="jabber:iq:register">
<username/><password/><email/><name/>
<x xmlns="jabber:x:data" type="form">
<title>XMPP Client Registration</title>
<instructions>Please provide the following information</instructions>
<field var="FORM_TYPE" type="hidden">
<value>jabber:iq:register</value>
</field>
<field var="username" type="text-single" label="Username">
<required/></field>
<field var="name" type="text-single" label="Full name"/>
<field var="email" type="text-single" label="Email"/>
<field var="password" type="text-private" label="Password">
<required/>
</field>
</x>
</query>
</iq>
5、客户端接收到服务端发送的申请单后,并填写回复:
<iq id="69Bxy-1" to="hytest240" type="set">
<query xmlns="jabber:iq:register">
<username>test</username>
<email></email>
<name></name>
<password>123456</password>
</query>
</iq>
6、注册完成后,服务端返回成功这里没有做出任何消息,仅仅只是回复。
<iq type="result" id="69Bxy-1" from="hytest240" to="hytest240/9fd61155"/>
IQRegisterHandler
IQRegisterHandler位于org.jivesoftware.openfire.handler中。该类主要处理客户端注册信息。
该类中有两个比较重要方法initialize、handleIQ。接下来看这两个方法。
initialize
该方法主要是做初始化注册模板。这个注册模板就是在上面提到的需要发送给客户端申请注册的深表表单。源码如下:
@Overridepublic void initialize(XMPPServer server) {super.initialize(server);userManager = server.getUserManager();rosterManager = server.getRosterManager();if (probeResult == null) {// Create the basic element of the probeResult which contains the basic registration// information (e.g. username, passoword and email)probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:register"));probeResult.addElement("username");probeResult.addElement("password");probeResult.addElement("email");probeResult.addElement("name");// Create the registration form to include in the probeResult. The form will include// the basic information plus name and visibility of name and email.// TODO Future versions could allow plugin modules to add new fields to the form final DataForm registrationForm = new DataForm(DataForm.Type.form);registrationForm.setTitle("XMPP Client Registration");registrationForm.addInstruction("Please provide the following information");final FormField fieldForm = registrationForm.addField();fieldForm.setVariable("FORM_TYPE");fieldForm.setType(FormField.Type.hidden);fieldForm.addValue("jabber:iq:register");final FormField fieldUser = registrationForm.addField();fieldUser.setVariable("username");fieldUser.setType(FormField.Type.text_single);fieldUser.setLabel("Username");fieldUser.setRequired(true);final FormField fieldName = registrationForm.addField(); fieldName.setVariable("name");fieldName.setType(FormField.Type.text_single);fieldName.setLabel("Full name");if (UserManager.getUserProvider().isNameRequired()) {fieldName.setRequired(true);}final FormField fieldMail = registrationForm.addField();fieldMail.setVariable("email");fieldMail.setType(FormField.Type.text_single);fieldMail.setLabel("Email");if (UserManager.getUserProvider().isEmailRequired()) {fieldMail.setRequired(true);}final FormField fieldPwd = registrationForm.addField();fieldPwd.setVariable("password");fieldPwd.setType(FormField.Type.text_private);fieldPwd.setLabel("Password");fieldPwd.setRequired(true);// Add the registration form to the probe result.probeResult.add(registrationForm.getElement());}// See if in-band registration should be enabled (default is true).registrationEnabled = JiveGlobals.getBooleanProperty("register.inband", true);// See if users can change their passwords (default is true).canChangePassword = JiveGlobals.getBooleanProperty("register.password", true);}
handleIQ
handleIQ方法,方法有四个步骤。
1、判断用户是否已经登陆。如果在session已经存在该用户发送错误消息反馈客户端:
PacketError.Condition.internal_server_error
2、获取IQ消息包的消息类型,如果是type=get那就是客户端需要获取申请表了。然
后,服务端封装这个表单,转成成XMPP消息发送给客户端。
3、当获取到的IQ消息包的消息类型给set(type=set)。那么就是客户点填写完了注册
表单,发送给服务端了。上面描述注册流程的第4步就是提交表单了。源码就不在
贴出来了,这个比较简单。只是一些判断校验比较多。
4、当所有的校验都正确,一切注册流程都正常的话。服务端就该返回第6点消息了。
当然在代码执行过程(业务处理,消息校验等)可能会产生些异常。处理异常的信息
这里把代码贴出来下,大家也可以自己去看源码:
catch (UserAlreadyExistsException e) {reply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.conflict);}catch (UserNotFoundException e) {reply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.bad_request);}catch (StringprepException e) {// The specified username is not correct according to the stringprep specsreply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.jid_malformed);}catch (IllegalArgumentException e) {// At least one of the fields passed in is not validreply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.not_acceptable);Log.warn(e.getMessage(), e);}catch (UnsupportedOperationException e) {// The User provider is read-only so this operation is not allowedreply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.not_allowed);}catch (Exception e) {// Some unexpected error happened so return an internal_server_errorreply = IQ.createResultIQ(packet);reply.setChildElement(packet.getChildElement().createCopy());reply.setError(PacketError.Condition.internal_server_error);Log.error(e.getMessage(), e);}
这里出现的PacketError这样的消息包错误对象,在以后的源码中会继续写博客,希望大家多多关照...
注册表单配置
在上面讲解用户注册的流程的时候,相信大家都看到了,用户注册的时候服务端会发送很长的一连串表单要客户端来填写。实际上吗,在openfire官方也不一定确定,世界各地使用注册到底需要哪些属性,所以给出来的注册模板可能会不适合所有的人来使用。那么怎么来修改注册模板呢。
然而在openfire控制管理台,也提供了用户注册表单的配置。在管理台目录:
用户/组->RegistrationProperties这个目录下。截图如下:
Ok,这里面有很多关于注册的使用相关信息。如下几个:
1、RegistrationSettings
2、RegistrationNotification Contacts
3、WelcomeMessage
4、DefaultGroup
5、Sign-Up PageHeader Text
在本章就,本人则挑几个给大家一起分析下。其余的大家可以自己跟踪下源码。
Registration Settings
RegistrationSettings是设置注册配置信息。
这里有禁用使用email,当然也可以添加使用,其他的属性,比如地址,邮编等。
Welcome Message
注册完成后,反馈欢迎词等等。
Default Group
注册完成后,添加到哪些默认组。关于默认组,以后再说。
.......
好了,注册这块就不谈了。
OpenFire源码学习之六:用户注册相关推荐
- OpenFire源码学习之七:组与花名册
Group 在openfire中的gorop--组,也可以理解为共享组.什么叫共享组呢.当有一个组名字为"学习组",当其他用户加入这个组的时候,那么他们会自动成为相互的好友.实际上 ...
- OpenFire源码学习之十九:在openfire中使用redis插件(上)
Redis插件 介绍 Redis是目前比较流行的NO-SQL,基于K,V的数据库系统.关于它的相关操作信息,本人这里就不做重复了,相关资料可以看这个网站http://www.redis.io/(官网) ...
- OpenFire源码学习之二十一:openfie对用户的优化(上)
用户类 优化用户主要是要解决用户的连接量.已经对用户的访问速度和吞吐量. 预初始化 在前面的带面中提出来了用户的预初始化.这里就不在贴出来了.下面将redis用户库连接池处理贴出来UserJedisP ...
- OpenFire源码学习之二十九:openfire集群配置
集群 Openfire的给集群提供了多种方案.一种是基于Hazelcast插件,还有基于Oracle的coherence插件. Oracle的coherence插件中文开发文档:http://down ...
- (转)OpenFire源码学习之十八:IOS离线推送
转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...
- OpenFire源码学习之四:openfire的启动流程
openfire启动 ServerStarter 启动流程图: 启动的总入口在ServerStarter的main方法中.通过上图首先它会先加载它所需要的jar文件.最后通过java反射机制将XMPP ...
- OpenFire源码学习之五:用户登录
登陆 登陆认证,客户端发送认SASL证消息: <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns: ...
- OpenFire源码学习之二十二:openfie对用户的优化(下)
用户名片 在预初始化中,贴出来用户名片的程序.这里也一样不在重复. 首先同样先修改系统属性: provider.vcard.className org.jivesoftware.util.redis. ...
- OpenFire源码学习之二十五:消息回执与离线消息(下)
这一篇紧接着上面继续了. 方案二 基于redis的消息回执.主要流程分为下面几个步骤: 1)将消息暂存储与redis中,设置好消息的过期时间 2)客户端回执消息id来消灭暂存的消息 3)开通单独线程论 ...
最新文章
- 昨夜,5G R16标准正式冻结!5G物联网扬帆起航
- 某设备产品漏洞挖掘-从JS文件挖掘RCE
- 答网友问:如果用 OData 就能直接和 SAP 系统互通,BTP 和 CPI 这样的平台意义在哪里呢?
- PHP,如何防止同一用户同一时间多次登录
- 初始Windows程序
- MariaDB日志审计 帮你揪出内个干坏事儿的小子
- Linux系统学习之 三:新手必须掌握的Linux命令3
- 如何选择华为MATE 30 PRO 5G和P40 PRO?
- SpringMVC扩展
- 拓端tecdat|Python用PyMC3实现贝叶斯线性回归模型
- 功能丰富的 Perl: 一行程序
- hdu---2087---剪花布条
- IDEA中将WEB-INF\lib下的Jar包添加到项目中
- PHP复习第三天-文件上传
- 5g的八大关键指标_5g的八大关键指标_2019世界5G大会:这些你要先知道
- 微信小程序云函数使用方法
- Uconn DataMining Math5671 课程小记(1)
- thinkphp用phpqrcode生成二维码(含中间带logo、临时二维码)或生成微信二维码海报的方法
- 红楼梦人物出场次数统计
- STM32WL无线Lora