(转)OpenFire源码学习之五:用户登录
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413377
登陆
登陆认证,客户端发送认SASL证消息:
- <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>
服务器得到客户端给出的SASL认证机制回答。首先将它存储起来。
C给出的认证机制为DIGEST-MD5,又服务器发起盘问。
- <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
- cmVhbG09IjhudG1vcnYxZXA0d2djeSIsbm9uY2U9InpydUNlS000YXJQU3N3Tm1MVFRacFdNWEdrYUdQQlhqdGZVY3ZRbXoiLHFvcD0iYXV0aCIsY2hhcnNldD11dGYtOCxhbGdvcml0aG09bWQ1LXNlc3M=
- </challenge>
既然服务器发出了盘问,客户端自然需要返回回答了,下面是客户端回答的内容
- <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
- Y2hhcnNldD11dGYtOCx1c2VybmFtZT0idGVzdDEiLHJlYWxtPSI4bnRtb3J2MWVwNHdnY3kiLG5vbmNlPSJ6cnVDZUtNNGFyUFNzd05tTFRUWnBXTVhHa2FHUEJYanRmVWN2UW16IixuYz0wMDAwMDAwMSxjbm9uY2U9Ik9DZ1cyb2ZsajVDN0I1TUc1MVFZQXRYcnRHbitGR1hxaW1Uc01vbG0iLGRpZ2VzdC11cmk9InhtcHAvOG50bW9ydjFlcDR3Z2N5IixtYXhidWY9NjU1MzYscmVzcG9uc2U9NTNhNTJkNjE0M2Q5ZjUwMzNkYmRhOWRkYmUwMDBhYTUscW9wPWF1dGgsYXV0aHppZD0idGVzdDEi
- </response>
不知道这一问一答,问的是什么内容。应该就是用户名密码校验了。不管怎样,客户端回答是正确的。应该是个用户名的加密字符串吧。
在这个过程中 查找用户的可用性,先将从缓存lockOutCache中查找。根据最近登陆时间段,查找用户是否已经存在,如果不存在,就从数据中查找
- SELECT name,startTime,endTime FROM ofUserFlag WHERE username=? AND name='lockout'
既然客户端回答正确,那么服务端又怎么作答呢?
- <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
- cnNwYXV0aD1lNWIzYjJkMjk1NjRmMTIxNDEwOWRmZTA5MTIzNDk2Nw==
- </success>
告知回答成功
SASL认证成功,设置本地客户端认证内容
- if (session instanceof ClientSession) {
- ((LocalClientSession) session).setAuthToken(new AuthToken(username));
这是认证成功了。
如果认证失败,很简单服务器直接关闭了会话:
- private static void authenticationFailed(LocalSession session) {
- StringBuilder reply = new StringBuilder(80);
- reply.append("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- reply.append("<not-authorized/></failure>");
- session.deliverRawText(reply.toString());
- // Give a number of retries before closing the connection
- Integer retries = (Integer) session.getSessionData("authRetries");
- if (retries == null) {
- retries = 1;
- }
- else {
- retries = retries + 1;
- }
- session.setSessionData("authRetries", retries);
- if (retries >= JiveGlobals.getIntProperty("xmpp.auth.retries", 3) ) {
- // Close the connection
- session.close();
- }
- }
这一段会话结束,客户端发送消息:
- <stream:stream to="8ntmorv1ep4wgcy" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
因为客户端已经认证成功,服务端就又打开一个新的流,并提供新的流功能,如资源约束和会话建立。请注意,资源约束和会话建立应该只提供给客户(即不用于服务器或外部元件)
以下是服务器邀请绑定资源:
- <?xml version='1.0' encoding='UTF-8'?>
- <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="8ntmorv1ep4wgcy" id="2884481a"
- xml:lang="en"
- version="1.0">
- <stream:features>
- <compression xmlns="http://jabber.org/features/compress">
- <method>zlib</method>
- </compression>
- <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>
- <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
- </stream:features>
Ok,既然服务器发送资源绑定邀请了。看下客户端发送的内容吧:
- <iq id="wSBRk-4" type="set">
- <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
- <resource>Smack</resource>
- <terminal>android</terminal>
- </bind>
- </iq>
IQ设置resorcr节点为资源内容
Terminal是本人自己加上的资源终端标识码。
在服务服端,关于IQHandler的子类有很多,当服务器接收到了绑定的请求。处理会交给
IQBindHandler来处理。
节点+域+资源+标识组成了新的JID。通过JID从本地路由中查找的会话是否存在。
如果存在,会刷出错误。这时候让客户端选择是否继续。
当然,这里登陆并没有冲突。我们继续!
没有存在其他的会话后,开始设置有效的身份验证令牌和资源名称初始化会话。这会自动升级会话的状态,以通过身份验证,使许多功能,直到认证(获得经理为例)不可用。
- public void setAuthToken(AuthToken auth, String resource, String terminal) {
- setAddress(new JID(auth.getUsername(), getServerName(), resource, terminal));
- authToken = auth;
- setStatus(Session.STATUS_AUTHENTICATED);
- // Set default privacy list for this session
- setDefaultList(PrivacyListManager.getInstance().getDefaultPrivacyList(auth.getUsername()));
- // Add session to the session manager. The session will be added to the routing table as well
- sessionManager.addSession(this);
- }
第一先设置地址
设置会话状态为3
设置用于会话的用户的默认隐私列表。如果没有活动列表为会话设置该列表被处理。
最后,添加一个新的会话来进行管理。该会话已经通过认证和资源约束已经完成。
- public void addSession(LocalClientSession session) {
- // Remove the pre-Authenticated session but remember to use the temporary ID as the key
- localSessionManager.getPreAuthenticatedSessions().remove(session.getStreamID().toString());
- // Add session to the routing table (routing table will know session is not available yet)
- routingTable.addClientRoute(session.getAddress(), session);
- SessionEventDispatcher.EventType event = session.getAuthToken().isAnonymous() ?
- SessionEventDispatcher.EventType.anonymous_session_created :
- SessionEventDispatcher.EventType.session_created;
- // Fire session created event.
- SessionEventDispatcher.dispatchEvent(session, event);
- if (ClusterManager.isClusteringStarted()) {
- // Track information about the session and share it with other cluster nodes
- sessionInfoCache.put(session.getAddress().toString(), new ClientSessionInfo(session));
- }
- }
好了,到了这个过程。绑定资源过程结束了。系统返回一个完成操作的报告给客户端。看下内容:
- <iq type="result" id="2W0UG-4" to="8ntmorv1ep4wgcy/4294fc5d">
- <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
- <jid>test1@8ntmorv1ep4wgcy/Smack#android</jid>
- </bind>
- </iq>
这时候的type为result
返回的消息已经告知,时间调度到侦听器。
这时候的用户状态为:<presencetype="unavailable"/>
客户端消息:
- <iq id="2W0UG-5" type="set">
- <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
- </iq>
以上客户端请求会话激活。
下面服务端返回会话激活:
- <iq id="2W0UG-5" type="set" from="test1@8ntmorv1ep4wgcy/Smack#android">
- <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
- </iq>
所有登陆都完成了。
(转)OpenFire源码学习之五:用户登录的更多相关文章
- (转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651 Group 在openfire中的gorop——组,也可以理解为共享组.什 ...
- (转)OpenFire源码学习之二十七:Smack源码解析
转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...
- (转)OpenFire源码学习之十八:IOS离线推送
转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...
- (转)OpenFire源码学习之十:连接管理(上)
转:http://blog.csdn.net/huwenfeng_2011/article/details/43415827 关于连接管理分为上下两部分 连接管理 在大并发环境下,连接资源 需要随着用 ...
- (转)OpenFire源码学习之六:用户注册
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413509 用户注册 注册流程: 1.客户端进行握手给服务端发送连接消息: <s ...
- (转)OpenFire源码学习之四:openfire的启动流程
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233 openfire启动 ServerStarter 启动流程图: 启动的总入 ...
- (转)即时通讯IM OpenFire源码学习之三:在Eclipse中构建源码
转:http://blog.csdn.net/huwenfeng_2011/article/details/43412617 源码搭建 下载地址: 地址:http://www.igniterealti ...
- Flask学习之五 用户登录
英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins 中文翻译地址:http:// ...
- (转)OpenFire源码学习之八:MUC用户聊天室
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413817 MUC 房间属性设置 以上属性存储在MUCPersistenceManag ...
随机推荐
- POJ 2808 校门外的树(线段树入门)
题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...
- 使用node-static运行vue打包文件dist
vue打包后的文件dist,如果想上线之前查看效果,方法如下: npm install -g node-static 进入到dist文件夹,运行static命令 打开上面地址
- Database基础(五):使用binlog日志、XtraBackup备份工具、MySQL AB复制
一.使用binlog日志 目标: 利用binlog恢复库表,要求如下: 启用binlog日志 创建db1库tb1表,插入3条记录 删除tb1表中刚插入的3条记录 使用mysqlbinlog恢复删除的3 ...
- windows2003 disk mirror failed redundency
操作前請確認 mirror 磁盤已備份 windows2003 disk mirror failed redundency時,offline + online並不可以自動修復. 需要offline f ...
- shell从字符串中提取子串(正则表达式)
通过试验,可以通过grep.sed两种方式实现. 假设需要提取libgcc-4.8.5-4.h5.x86_64.rpm中的版本号. grep echo "libgcc-4.8.5-4.h5. ...
- 创建线程方法&守护线程
创建线程方法1. class mythread extends Thread{ 重写run方法 } mythread m=new mythread () 启动:m.start() 创建线程方法2. c ...
- mac查看python安装路径
1.terminal : input: which Python 或者 which Python3 2.terminal: input : python --->import sys --- ...
- 13.JMeter 参数化、检查点、集合点
参数化:简单的来理解一下,我们录制了一个脚本,这个脚本中有登录操作,需要输入用户名和密码,假如系统不允许相同的用户名和密码同时登录,或者想更好的模拟多个用户来登录系统. 这个时候就需要对用户名和密码进 ...
- Linux的各个发行版本(一)
三大流派 1.Slackware SUSE Linux Enterprise Server (SLES) OpenSuse桌面 2.debian 迄今为止最遵循GNU规范的Linux系统 Ubuntu ...
- 标准模板库(STL)学习探究之Multimap容器
C++ Multimaps和maps很相似,但是MultiMaps允许重复的元素.(具体用法请参考map容器) 函数列表: begin() 返回指向第一个元素的迭代器 cle ...