OpenFire源码学习之五:用户登录
来源:互联网 发布:surface适合编程吗 编辑:程序博客网 时间:2024/05/22 06:06
登陆
登陆认证,客户端发送认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源码学习之六:用户注册
- openfire源码解读-用户登录
- OpenFire源码学习之八:MUC用户聊天室
- OpenFire源码学习之二十一:openfie对用户的优化(上)
- OpenFire源码学习之二十二:openfie对用户的优化(下)
- OpenFire源码学习之二十八:与其他系统的用户整合
- OpenFire源码学习之四:openfire的启动流程
- OpenFire源码学习之二十九:openfire集群配置
- OpenFire源码学习之三十一:使用Tsung测试openfire(上)
- OpenFire源码学习之三十二:使用Tsung测试openfire(下)
- OpenFire源码学习之二十九:openfire集群配置
- OpenFire源码学习之二:Mina基础知识
- OpenFire源码学习之十三:消息处理
- OpenFire源码学习之十四:插件管理
- OpenFire源码学习之十五:插件开发
- OpenFire源码学习之十六:wildfire
- OpenFire源码学习之三十三:windows打包
- const int * pi 、int const * pi与int * const pi及其操作
- 黑马程序员------C语言-----初识C语言
- Object-c 数组总结
- poj3299 Humidex
- (hdu step 2.2.8)N!Again(求N!的阶乘%2009以后的结果)
- OpenFire源码学习之五:用户登录
- BZOJ 3011 Usaco2012 Dec Running Away From the Barn 可并堆
- Java语言程序设计-基础篇-5.6习题-显示模式
- 小马哥----珍米ZMi_S801 仿米4 刷机开机界面图与外观图,国产机6582芯片
- 【VB.NET】全局观概括
- 【POJ-1005】I Think I Need a Houseboat
- Managing time
- NSTimer的启动与停止、暂停和继续
- js小知识