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

            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é)果(操作成功)

            #如何注銷一個(gè)用戶
            注銷一個(gè)用戶必須在完成與服務(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é):
            注冊用戶和更改或者注銷用戶的一個(gè)區(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是一個(gè)Iqhandler, 它實(shí)現(xiàn)的是handleIqID( Stanza *stanza, int context )接口,而不是handleIq( Stanza *stanza )接口,其中context實(shí)質(zhì)上為iqHandler具體實(shí)現(xiàn)中的子操作類型,在registration中分別為fetchRegisterFiled, createAccount, changePassword, removeAccount.

            對一個(gè)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 閱讀(4567) 評論(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);
            錯(cuò)誤提示在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信息時(shí)候的to屬性,這在服務(wù)器是gtalk server的時(shí)候是有用的,如果我們的服務(wù)器地址設(shè)置為talk.google.com,則header()方法默認(rèn)to="talk.google.com",這是錯(cuò)誤的,應(yīng)該為to="gmail.com".

            2. sasl failed。登陸的時(shí)候需要sasl 驗(yàn)證,如果服務(wù)器為gtalk server, 當(dāng)你接收到服務(wù)器發(fā)送的以下信息的時(shí)候
            (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ù)器通訊 - 建立會(huì)話”,里面詳細(xì)描述了如何登陸到gtalk服務(wù)器.

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

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


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            97久久精品无码一区二区| 久久精品国产亚洲av高清漫画 | 久久久精品人妻一区二区三区四| 久久久久久久久波多野高潮| 国产偷久久久精品专区| 久久亚洲国产欧洲精品一| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区| 久久综合久久综合九色| 国产免费久久精品99re丫y| 亚洲伊人久久精品影院| 99久久国语露脸精品国产| 久久久久亚洲av成人无码电影| 亚洲午夜久久久久久噜噜噜| 日本久久久久久中文字幕| 久久久午夜精品福利内容| 国产精品久久久久aaaa| 一级做a爰片久久毛片看看| 久久综合丝袜日本网| 99精品国产99久久久久久97| 精品久久久久中文字幕一区| 精品久久久久久亚洲精品| 模特私拍国产精品久久| 91精品国产91久久久久久| 久久久久99精品成人片欧美| 日韩电影久久久被窝网| 久久99热精品| 亚洲精品白浆高清久久久久久| 精品久久久久久国产三级| 久久久久四虎国产精品| 国产V综合V亚洲欧美久久| 精品国产99久久久久久麻豆| 欧美亚洲日本久久精品| 久久国产成人亚洲精品影院| 青青草国产精品久久久久| 九九99精品久久久久久| 97久久超碰成人精品网站| 日韩精品久久无码中文字幕| 精品人妻伦九区久久AAA片69| 亚洲伊人久久成综合人影院| 久久伊人色| 久久久久久久综合狠狠综合|