zoukankan      html  css  js  c++  java
  • (转)OpenFire源码学习之五:用户登录

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413377

    登陆

    登陆认证,客户端发送认SASL证消息:

    [html] view plain copy
     
    1. <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>  

    服务器得到客户端给出的SASL认证机制回答。首先将它存储起来。

    C给出的认证机制为DIGEST-MD5,又服务器发起盘问。

    [html] view plain copy
     
    1. <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">  
    2. cmVhbG09IjhudG1vcnYxZXA0d2djeSIsbm9uY2U9InpydUNlS000YXJQU3N3Tm1MVFRacFdNWEdrYUdQQlhqdGZVY3ZRbXoiLHFvcD0iYXV0aCIsY2hhcnNldD11dGYtOCxhbGdvcml0aG09bWQ1LXNlc3M=  
    3. </challenge>  

    既然服务器发出了盘问,客户端自然需要返回回答了,下面是客户端回答的内容

    [html] view plain copy
     
    1.  <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">  
    2. Y2hhcnNldD11dGYtOCx1c2VybmFtZT0idGVzdDEiLHJlYWxtPSI4bnRtb3J2MWVwNHdnY3kiLG5vbmNlPSJ6cnVDZUtNNGFyUFNzd05tTFRUWnBXTVhHa2FHUEJYanRmVWN2UW16IixuYz0wMDAwMDAwMSxjbm9uY2U9Ik9DZ1cyb2ZsajVDN0I1TUc1MVFZQXRYcnRHbitGR1hxaW1Uc01vbG0iLGRpZ2VzdC11cmk9InhtcHAvOG50bW9ydjFlcDR3Z2N5IixtYXhidWY9NjU1MzYscmVzcG9uc2U9NTNhNTJkNjE0M2Q5ZjUwMzNkYmRhOWRkYmUwMDBhYTUscW9wPWF1dGgsYXV0aHppZD0idGVzdDEi  
    3. </response>  

    不知道这一问一答,问的是什么内容。应该就是用户名密码校验了。不管怎样,客户端回答是正确的。应该是个用户名的加密字符串吧。

    在这个过程中 查找用户的可用性,先将从缓存lockOutCache中查找。根据最近登陆时间段,查找用户是否已经存在,如果不存在,就从数据中查找

    [sql] view plain copy
     
    1. SELECT name,startTime,endTime FROM ofUserFlag WHERE username=? AND name='lockout'  

    既然客户端回答正确,那么服务端又怎么作答呢?

    [html] view plain copy
     
    1. <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">  
    2. cnNwYXV0aD1lNWIzYjJkMjk1NjRmMTIxNDEwOWRmZTA5MTIzNDk2Nw==  
    3. </success>  

    告知回答成功

    SASL认证成功,设置本地客户端认证内容

    [java] view plain copy
     
    1. if (session instanceof ClientSession) {  
    2.             ((LocalClientSession) session).setAuthToken(new AuthToken(username));  

    这是认证成功了。

    如果认证失败,很简单服务器直接关闭了会话:

    [java] view plain copy
     
    1. private static void authenticationFailed(LocalSession session) {  
    2.         StringBuilder reply = new StringBuilder(80);  
    3.         reply.append("<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl">");  
    4.         reply.append("<not-authorized/></failure>");  
    5.         session.deliverRawText(reply.toString());  
    6.         // Give a number of retries before closing the connection  
    7.         Integer retries = (Integer) session.getSessionData("authRetries");  
    8.         if (retries == null) {  
    9.             retries = 1;  
    10.         }  
    11.         else {  
    12.             retries = retries + 1;  
    13.         }  
    14.         session.setSessionData("authRetries", retries);  
    15.         if (retries >= JiveGlobals.getIntProperty("xmpp.auth.retries", 3) ) {  
    16.             // Close the connection  
    17.             session.close();  
    18.         }  
    19.     }  

    这一段会话结束,客户端发送消息:

    [html] view plain copy
     
    1. <stream:stream to="8ntmorv1ep4wgcy" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">  

    因为客户端已经认证成功,服务端就又打开一个新的流,并提供新的流功能,如资源约束和会话建立。请注意,资源约束和会话建立应该只提供给客户(即不用于服务器或外部元件)

    以下是服务器邀请绑定资源:

    [html] view plain copy
     
    1. <?xml version='1.0' encoding='UTF-8'?>  
    2. <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="8ntmorv1ep4wgcy" id="2884481a"   
    3. xml:lang="en"   
    4. version="1.0">  
    5. <stream:features>  
    6. <compression xmlns="http://jabber.org/features/compress">  
    7. <method>zlib</method>  
    8. </compression>  
    9. <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>  
    10. <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>  
    11. </stream:features>  

    Ok,既然服务器发送资源绑定邀请了。看下客户端发送的内容吧:

    [html] view plain copy
     
    1. <iq id="wSBRk-4" type="set">  
    2. <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">  
    3. <resource>Smack</resource>  
    4. <terminal>android</terminal>  
    5. </bind>  
    6. </iq>  

    IQ设置resorcr节点为资源内容

    Terminal是本人自己加上的资源终端标识码。

    在服务服端,关于IQHandler的子类有很多,当服务器接收到了绑定的请求。处理会交给

    IQBindHandler来处理。

    节点+域+资源+标识组成了新的JID。通过JID从本地路由中查找的会话是否存在。

    如果存在,会刷出错误。这时候让客户端选择是否继续。

    当然,这里登陆并没有冲突。我们继续!

    没有存在其他的会话后,开始设置有效的身份验证令牌和资源名称初始化会话。这会自动升级会话的状态,以通过身份验证,使许多功能,直到认证(获得经理为例)不可用。

    [java] view plain copy
     
    1. public void setAuthToken(AuthToken auth, String resource, String terminal) {  
    2.        setAddress(new JID(auth.getUsername(), getServerName(), resource, terminal));  
    3.        authToken = auth;  
    4.        setStatus(Session.STATUS_AUTHENTICATED);  
    5.   
    6.        // Set default privacy list for this session  
    7.        setDefaultList(PrivacyListManager.getInstance().getDefaultPrivacyList(auth.getUsername()));  
    8.        // Add session to the session manager. The session will be added to the routing table as well  
    9.        sessionManager.addSession(this);  
    10.    }  

    第一先设置地址

    设置会话状态为3

    设置用于会话的用户的默认隐私列表。如果没有活动列表为会话设置该列表被处理。

    最后,添加一个新的会话来进行管理。该会话已经通过认证和资源约束已经完成。

    [java] view plain copy
     
    1. public void addSession(LocalClientSession session) {  
    2.         // Remove the pre-Authenticated session but remember to use the temporary ID as the key  
    3.         localSessionManager.getPreAuthenticatedSessions().remove(session.getStreamID().toString());  
    4.         // Add session to the routing table (routing table will know session is not available yet)  
    5.         routingTable.addClientRoute(session.getAddress(), session);  
    6.         SessionEventDispatcher.EventType event = session.getAuthToken().isAnonymous() ?  
    7.                 SessionEventDispatcher.EventType.anonymous_session_created :  
    8.                 SessionEventDispatcher.EventType.session_created;  
    9.         // Fire session created event.  
    10.         SessionEventDispatcher.dispatchEvent(session, event);  
    11.         if (ClusterManager.isClusteringStarted()) {  
    12.             // Track information about the session and share it with other cluster nodes  
    13.             sessionInfoCache.put(session.getAddress().toString(), new ClientSessionInfo(session));  
    14.         }  
    15.     }  

    好了,到了这个过程。绑定资源过程结束了。系统返回一个完成操作的报告给客户端。看下内容:

    [html] view plain copy
     
    1. <iq type="result" id="2W0UG-4" to="8ntmorv1ep4wgcy/4294fc5d">  
    2.   <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">  
    3.     <jid>test1@8ntmorv1ep4wgcy/Smack#android</jid>  
    4.   </bind>  
    5. </iq>  

    这时候的type为result

    返回的消息已经告知,时间调度到侦听器。

    这时候的用户状态为:<presencetype="unavailable"/>

    客户端消息:

    [html] view plain copy
     
    1. <iq id="2W0UG-5" type="set">  
    2.   <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>  
    3. </iq>  

    以上客户端请求会话激活

    下面服务端返回会话激活

    [html] view plain copy
     
    1. <iq id="2W0UG-5" type="set" from="test1@8ntmorv1ep4wgcy/Smack#android">  
    2.   <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>  
    3. </iq>  

    所有登陆都完成了。

  • 相关阅读:
    javaApi Swagger配置
    java跨域配置
    applation.properties与applation.yml关于sql数据库连接配置的区别
    SpringBoot学习记录一
    Centos命令行报bash:.....:command not found的解决办法
    Referenced file contains errors (http://JAVA.sun.com/xml/ns/j2ee/web-app_2_5.xsd).
    C# 两种封装的区别
    此 ObjectContext 实例已释放,不可再用于需要连接的操作。
    .net MVC ajax传递数组
    正则表达式移除首部尾部多余字符
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/7160382.html
Copyright © 2011-2022 走看看