• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woomsg

            在路上

            gloox代碼分析3 - 注冊模塊

            #jabber協議中如何注冊一個用戶?
            首先要與服務器建立一個連接, 在完成TLS握手之后就可以進行注冊了,為什么不需要SASL握手呢?因為SASL握手只針對已經注冊的用戶在登陸服務器的時候使用.(修改密碼和刪除用戶的時候需要SASL握手)
            下面以openfire作為服務器,注冊一個用戶的過程如下:
            (假設已經完成了TLS握手)
            1. ( C->S )
            <stream:stream
                to='ziz-wrks-tfsxp1'
                xmlns='jabber:client'
                xmlns:stream='http://etherx.jabber.org/streams' 
                xml:lang='en'
                version='1.0'>

            TLS握手結束后, 發送新的'hello'消息

            2. ( S->C )
            <stream:stream
                xmlns:stream='http://etherx.jabber.org/streams'
                xmlns='jabber:client'
                from='ziz-wrks-tfsxp1'
                id='b691538a'
                xml:lang='en' version='1.0'/>

            Server回應Client的hello消息.

            3. ( S->C )
            <stream:features>
              <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
                <mechanism>DIGEST-MD5</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>

            服務器支持的features(可以register)

            4. ( C->S )
            <iq type='get' id='uid1'>
              <query xmlns='jabber:iq:register'/>
            </iq>

            客戶端請求注冊
            5. ( S->C )
            <iq type='result' id='uid1'>
              <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 label='Username' var='username' type='text-single'>
                    <required/>
                  </field>
                  <field label='Full name' var='name' type='text-single'/>
                  <field label='Email' var='email' type='text-single'/>
                  <field label='Password' var='password' type='text-private'>
                    <required/>
                  </field>
                </x>
              </query>
            </iq>

            服務器返回注冊需要的fields
            (其中元素x里面的數據是擴展性的數據表但,暫時忽略)

            6. ( C->S )
            <iq id='uid2' type='set'>
              <query xmlns='jabber:iq:register'>
                <username>user3</username>
                <password>user@123</password>
                <name/>
                <email/>
              </query>
            </iq>

            用戶提交注冊信息.

            7. ( S->C )
            <iq type='result' id='uid2' to='ziz-wrks-tfsxp1/b691538a'/>

            服務器返回注冊結果

            #如何更改用戶密碼
            更改用戶密碼必須在完成與服務器的鏈接之后才能進行,也就是完成與服務器的TLS,SASl握手之后
            再進行.

            1. ( C->S )
            <iq type='set' id='uid3'>
              <query xmlns='jabber:iq:register'>
                <username>user23</username>
                <password>123456</password>
              </query>
            </iq>

            發送更改密碼的請求

            2. ( S->C )
            <iq type='result' id='uid3' to='user23@ziz-wrks-tfsxp1/2f21fd1f'/>

            返回處理結果(操作成功)

            #如何注銷一個用戶
            注銷一個用戶必須在完成與服務器的鏈接之后才能進行,也就是完成與服務器的TLS,SASl握手之后
            再進行.

            1. ( C->S )
            <iq type='set' id='uid3' from='testuser@ziz-wrks-tfsxp1/3a418274'>
               <query xmlns='jabber:iq:register'><remove/></query>
            </iq>

            發送注銷用戶的請求

            2. ( S->S )

            <iq type='result' id='uid3' to='testuser@ziz-wrks-tfsxp1/3a418274'/>

            返回處理結果(注銷成功)

            總結:
            注冊用戶和更改或者注銷用戶的一個區別就是注冊用戶不需要經過SASL握手,而更改和注銷用戶需要.
            也就是需要對用戶身份進行驗證.

            gloox的注冊模塊
            registration.h
            registration.cpp
            registrationhandler.h
            就是對上述協議的封裝,方便創建register stanza,并把收到的消息分發到相應的handler方法.

            gloox的client是如何處理xml流的呢?
            1. 連接到服務器后,使客戶端進入"receive mode",可以循環的接收數據.
            2. 數據流 [接收到的數據 handleReceiveData() ] -> [解析xml數據流,解析成不同的tag, parser()] -> [ 觸發handleTag(), 針對不同的tag分發到不同的handlers做不同的處理 ]
             - stream:stream - ...
             - stream:error - ...
             - Iq           - IqHandler
             - Presence - presenceHandler
             - Message - messageHandler 

            Iq消息的處理機制,以及trackID機制:

            實質上registration是一個Iqhandler, 它實現的是handleIqID( Stanza *stanza, int context )接口,而不是handleIq( Stanza *stanza )接口,其中context實質上為iqHandler具體實現中的子操作類型,在registration中分別為fetchRegisterFiled, createAccount, changePassword, removeAccount.

            對一個Iq Stanza的處理方式可以通過一般的IqHandler - xmlnamespace filer或者IqHandler - TrackID機制來處理.

            下面代碼展示了如何注冊/修改密碼/刪除用戶(服務器是openfire):
              1#include <iostream>
              2#include "registration.h" // gloox headers
              3#include "client.h"
              4#include "connectionlistener.h"
              5#include "logsink.h"
              6#include "loghandler.h"
              7
              8#pragma comment( lib, "gloox.lib" )
              9using namespace gloox;
             10
             11#define SERVERNAME   "xxxxxx"
             12#define HEADERTO     "xxxxxx"
             13
             14#define USERNAME     "user123"
             15#define PASSWORD     "user@123"
             16#define NEWPASSWORD  "123456"
             17
             18//
             19// three scenario3
             20// 1 - register user (Note: don't need SASL handshake)
             21// 2 - change password (Note: need SASL handshake)
             22// 3 - delete user (Note: need SASL handshake)
             23//
             24class RegisterImpl : public RegistrationHandler, ConnectionListener, LogHandler {
             25public:
             26  void run();
             27
             28  //implement RegistrationHandler
             29  void handleRegistrationFields( const JID& from, int fields, std::string instructions );
             30  void handleAlreadyRegistered( const JID& from );
             31  void handleRegistrationResult( const JID& from, RegistrationResult regResult );
             32  void handleDataForm( const JID& from, const DataForm &form );
             33  void handleOOB( const JID& from, const OOB& oob );
             34
             35  //implement ConnectionListener
             36  void onConnect();
             37  void onDisconnect( ConnectionError e );
             38  void onResourceBindError( ResourceBindError error );
             39  void onSessionCreateError( SessionCreateError error );
             40  bool onTLSConnect( const CertInfo& info );
             41  void onStreamEvent( StreamEvent event );
             42
             43  //implement LogHandler
             44  void handleLog( LogLevel level, LogArea area, const std::string& message );
             45
             46private:
             47  Registration* register_;
             48  Client* client_;
             49}
            ;
             50
             51void RegisterImpl::run() {
             52  client_ = new Client(SERVERNAME);
             53  client_->setHeaderTo(HEADERTO);
             54  client_->registerConnectionListener(this);
             55  register_ = new Registration( client_ );
             56  register_->registerRegistrationHandler( this );
             57  client_->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this  );
             58  
             59  // run scenario2 and scenario3 need enable username and
             60  // password to run SASL, scenario1 did not need.
             61  client_->setUsername(USERNAME);
             62  client_->setPassword(PASSWORD);
             63
             64  client_->connect();
             65
             66  delete register_;
             67  delete client_;
             68}

             69
             70void RegisterImpl::handleRegistrationFields( const JID& from, int fields, std::string instructions ) {
             71  // register account
             72  std::cout<<"impl# register instruction: "<<instructions<<std::endl;
             73  RegistrationFields vals;
             74  vals.username = USERNAME;
             75  vals.password = PASSWORD;
             76  register_->createAccount( fields, vals );
             77}

             78
             79void RegisterImpl::handleAlreadyRegistered( const JID& from ) {
             80  std::cout<<"impl# the count already exists."<<std::endl;
             81}

             82
             83void RegisterImpl::handleRegistrationResult( const JID& from, RegistrationResult regResult ) {
             84  if( regResult == RegistrationSuccess ) {
             85    std::cout<<"impl# operation success."<<std::endl;
             86  }
             else {
             87    std::cout<<"impl# operation failed."<<std::endl;
             88  }

             89
             90  client_->disconnect();
             91}

             92
             93void RegisterImpl::handleDataForm( const JID& from, const DataForm &form ) {
             94  //TODO:
             95}

             96
             97void RegisterImpl::handleOOB( const JID& from, const OOB& oob ) {
             98  //TODO:
             99}

            100
            101void RegisterImpl::onConnect() {
            102  std::cout<<"impl# connect to server success."<<std::endl;
            103  //operation
            104
            105  // scenario1 - register
            106  // this will invoke handleRegistrationResult() to createAccount
            107  // Note: doesn't need SASL handshake
            108  register_->fetchRegistrationFields(); 
            109
            110  // scenario2 - change password
            111  // Note: need SASL handshake, in gloox, set the username & password in clientbase, will
            112  //       run the SASL handshake.
            113  // register_->changePassword( client_->username(), NEWPASSWORD );
            114
            115  // scenario3 - delete account
            116  // Note: need SASL handshake,
            117  // register_->removeAccount();
            118}

            119
            120void RegisterImpl::onDisconnect( ConnectionError e ) {
            121  std::cout<<"impl# disconnected."<<std::endl;
            122}

            123
            124void RegisterImpl::onResourceBindError( ResourceBindError error ) {
            125  //TODO:
            126}

            127
            128void RegisterImpl::onSessionCreateError( SessionCreateError error ) {
            129  //TODO:
            130}

            131
            132bool RegisterImpl::onTLSConnect( const CertInfo& info ) {
            133  std::cout<<"impl# tls connect to server success."<<std::endl;
            134  return true;
            135}

            136
            137void RegisterImpl::onStreamEvent( StreamEvent event ) {
            138  //TODO:
            139}

            140
            141void RegisterImpl::handleLog( LogLevel level, LogArea area, const std::string& message ) {
            142  std::cout<<"impl-log# "<<message<<std::endl;
            143}

            144
            145int main( int argc, char* argv[] ) {
            146  RegisterImpl impl;
            147  impl.run();
            148  return 0;
            149}

            posted on 2008-11-06 12:59 ysong.lee 閱讀(4561) 評論(3)  編輯 收藏 引用

            Feedback

            # re: gloox代碼分析3 - 注冊模塊 2008-11-14 19:09 ly

            hao  回復  更多評論   

            # re: gloox代碼分析3 - 注冊模塊 2008-11-14 19:13 ly

            client_->setHeaderTo(HEADERTO);
            錯誤提示在client 里找不到setHeaderTo?????什么問題?
            我把你這句去掉后,改成
            client_->disableRoster();
            發現能注冊成功,但是,登陸提示:sasl failed。
            登陸不成功!~~~什么原因~~~望解答!~~  回復  更多評論   

            # re: gloox代碼分析3 - 注冊模塊 2008-11-18 13:01 ysong.lee

            1. 我對gloox進行了修改,client_->setHeaderTo(HEADERTO); 是自己添加的方法,目的是為了fix gloox不能連接到gtalk server的問題,通過修改,可以自己控制ClientBase::header()方法中在發送hello信息時候的to屬性,這在服務器是gtalk server的時候是有用的,如果我們的服務器地址設置為talk.google.com,則header()方法默認to="talk.google.com",這是錯誤的,應該為to="gmail.com".

            2. sasl failed。登陸的時候需要sasl 驗證,如果服務器為gtalk server, 當你接收到服務器發送的以下信息的時候
            (Server -> Client)
            <stream:features>
            <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
            <mechanism>PLAIN</mechanism>
            <mechanism>X-GOOGLE-TOKEN</mechanism>
            </mechanisms>
            </stream:features>

            需要進行sasl驗證,發送的驗證數據格式為:
            '\0'+username+'\0'+password 的base64編碼, username和password必須是經過認證的.
            例如:
            '\0' + 'ysong.lee@gmail.com' + '\0' + 123456 -> 經過base64編碼處理
            (Client -> Server)
            <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">
            AHlzb25nLmxlZUBnbWFpbC5jb20AeXNvbmdAMTk4NA==
            </auth>

            3. 如果還有疑問,可以參考我的另外一篇文章“如何利用jabber協議與gtalk服務器通訊 - 建立會話”,里面詳細描述了如何登陸到gtalk服務器.

            4. 做XMPP的程序,仔細閱讀從server到client和client的server的xml數據流,并參考標準協議,問題都可以解決:), 還有問題可以發email給我.

            @ly
              回復  更多評論   

            久久综合给合久久狠狠狠97色69 | 99久久精品免费看国产| 精品无码久久久久久尤物| 久久国产亚洲高清观看| 99久久精品免费看国产| 欧美亚洲另类久久综合婷婷| 久久综合久久自在自线精品自 | 日韩av无码久久精品免费| 欧美噜噜久久久XXX| 久久久久亚洲AV成人网人人软件| 亚洲午夜无码久久久久小说| 9久久9久久精品| 久久久久久国产a免费观看黄色大片 | 婷婷综合久久狠狠色99h| 99久久综合国产精品免费| 国产精品久久国产精麻豆99网站 | 久久精品亚洲男人的天堂| 五月丁香综合激情六月久久| 久久精品国产一区二区三区| 69SEX久久精品国产麻豆| 国产激情久久久久久熟女老人| 久久精品国产99久久香蕉| 香蕉久久av一区二区三区| 久久精品中文字幕大胸| 性做久久久久久久久久久| 亚洲天堂久久精品| 国产精品久久永久免费| 色偷偷久久一区二区三区| 久久精品国产清自在天天线| 亚洲天堂久久久| 热久久视久久精品18| 久久精品18| 伊人久久精品无码av一区| 亚洲狠狠婷婷综合久久久久| 久久婷婷色香五月综合激情| 久久精品国产亚洲av麻豆蜜芽 | 久久久久无码国产精品不卡| 国内精品久久久久影院网站| 999久久久国产精品| 韩国三级中文字幕hd久久精品| 久久久久亚洲精品无码网址|