• <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協(xié)議中如何注冊一個用戶?
            首先要與服務(wù)器建立一個連接, 在完成TLS握手之后就可以進(jìn)行注冊了,為什么不需要SASL握手呢?因?yàn)镾ASL握手只針對已經(jīng)注冊的用戶在登陸服務(wù)器的時候使用.(修改密碼和刪除用戶的時候需要SASL握手)
            下面以openfire作為服務(wù)器,注冊一個用戶的過程如下:
            (假設(shè)已經(jīng)完成了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握手結(jié)束后, 發(fā)送新的'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回應(yīng)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>

            服務(wù)器支持的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>

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

            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'/>

            服務(wù)器返回注冊結(jié)果

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

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

            發(fā)送更改密碼的請求

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

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

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

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

            發(fā)送注銷用戶的請求

            2. ( S->S )

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

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

            總結(jié):
            注冊用戶和更改或者注銷用戶的一個區(qū)別就是注冊用戶不需要經(jīng)過SASL握手,而更改和注銷用戶需要.
            也就是需要對用戶身份進(jìn)行驗(yàn)證.

            gloox的注冊模塊
            registration.h
            registration.cpp
            registrationhandler.h
            就是對上述協(xié)議的封裝,方便創(chuàng)建register stanza,并把收到的消息分發(fā)到相應(yīng)的handler方法.

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

            Iq消息的處理機(jī)制,以及trackID機(jī)制:

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

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

            下面代碼展示了如何注冊/修改密碼/刪除用戶(服務(wù)器是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  回復(fù)  更多評論   

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

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

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

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

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

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

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

            4. 做XMPP的程序,仔細(xì)閱讀從server到client和client的server的xml數(shù)據(jù)流,并參考標(biāo)準(zhǔn)協(xié)議,問題都可以解決:), 還有問題可以發(fā)email給我.

            @ly
              回復(fù)  更多評論   

            国内精品伊人久久久影院| 久久精品国产亚洲7777| 国产精品99久久久精品无码| 久久精品国产亚洲AV影院| 久久精品国产亚洲av麻豆图片 | 区久久AAA片69亚洲| 漂亮人妻被中出中文字幕久久| 国产成人久久精品一区二区三区| 久久久噜噜噜久久中文福利| 国内精品久久久久久久coent| 亚洲∧v久久久无码精品| 精品人妻伦九区久久AAA片69| 国产69精品久久久久9999APGF| 中文字幕一区二区三区久久网站| 久久免费看黄a级毛片| 久久99精品久久久久久野外| 久久99精品久久久久久动态图| 伊人久久五月天| 99久久精品免费看国产一区二区三区| 伊人精品久久久久7777| 亚洲成色999久久网站| 久久精品国产99久久久| 国产A三级久久精品| 色综合久久中文字幕综合网| 99久久99久久精品国产| 久久se精品一区二区| 国产精品9999久久久久| 亚洲va国产va天堂va久久| 欧美久久久久久| 女人高潮久久久叫人喷水| 人人狠狠综合久久亚洲| 久久久久女教师免费一区| 国产精品va久久久久久久| 99久久99这里只有免费的精品| 久久人爽人人爽人人片AV| 亚洲精品无码久久久久sm| 精品国产青草久久久久福利| 久久人人爽人人爽人人片AV麻烦| 亚洲乱码日产精品a级毛片久久| 青草久久久国产线免观| 久久夜色精品国产亚洲av|