#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" )
9
using 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
//
24
class RegisterImpl : public RegistrationHandler, ConnectionListener, LogHandler
{
25
public:
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
46
private:
47
Registration* register_;
48
Client* client_;
49
};
50
51
void 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
70
void 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
79
void RegisterImpl::handleAlreadyRegistered( const JID& from )
{
80
std::cout<<"impl# the count already exists."<<std::endl;
81
}
82
83
void 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
93
void RegisterImpl::handleDataForm( const JID& from, const DataForm &form )
{
94
//TODO:
95
}
96
97
void RegisterImpl::handleOOB( const JID& from, const OOB& oob )
{
98
//TODO:
99
}
100
101
void 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
120
void RegisterImpl::onDisconnect( ConnectionError e )
{
121
std::cout<<"impl# disconnected."<<std::endl;
122
}
123
124
void RegisterImpl::onResourceBindError( ResourceBindError error )
{
125
//TODO:
126
}
127
128
void RegisterImpl::onSessionCreateError( SessionCreateError error )
{
129
//TODO:
130
}
131
132
bool RegisterImpl::onTLSConnect( const CertInfo& info )
{
133
std::cout<<"impl# tls connect to server success."<<std::endl;
134
return true;
135
}
136
137
void RegisterImpl::onStreamEvent( StreamEvent event )
{
138
//TODO:
139
}
140
141
void RegisterImpl::handleLog( LogLevel level, LogArea area, const std::string& message )
{
142
std::cout<<"impl-log# "<<message<<std::endl;
143
}
144
145
int main( int argc, char* argv[] )
{
146
RegisterImpl impl;
147
impl.run();
148
return 0;
149
}