前言
现在网络游戏越来越多,绝大部分网络游戏都是需要登录注册这一功能的,登录注册一般使用弱联网,即HTTP来实现,由于只需要请求返回信息而不需要实时交互,所以我们选择了弱联网。
流程
我们会通过客户端来请求服务器登录注册,服务器根据客户端请求的类型来对数据库进行增删改查,并返回数据给客户端,客户端拿到服务端的信息实现具体的逻辑。
思路
1.我们会通过客户端请求时间戳来同步服务器和客户端的时间,当我们请求登录注册时,如果服务器和客户端的时间差大于一个限定,那么我们就不会让这个请求满足,这是因为我们的服务器处理的信息量是有限的,如果有人恶意攻击我们的服务器,比如发动POST攻击,一秒钟就能请求很多次服务器,会造成服务器的崩溃,我们就有必要限制双方进行通信的时间要求,只有在有效时间内的请求才会被接受。
2.我们请求登录注册信息的时候需要附带上时间戳--签名--设备号,时间戳上面说过了,签名是用于身份验证,我们通过时间戳和设备号组成一个签名,然后再通过MD5加密,然后传到服务器,服务器会将传来的签名进行解密,然后将传过来的时间戳和设备号以相同的方式生成签名,对比生成签名和传入的签名,如果一致,身份验证通过,这样就可以保证我们通讯的安全。
public
RetValue
Post([
FromBody
]
string
value)
{
RetValue
ret =
new
RetValue
();
JsonData
data =
JsonMapper
.ToObject(value);
//安全
long
t =
Convert
.ToInt64(data[
"t"
].ToString());
string
deviceUniqueIdentifier = data[
"deviceUniqueIdentifier"
].ToString();
string
deviceModel = data[
"deviceModel"
].ToString();
string
sign = data[
"sign"
].ToString();
//判断时间戳
if
(
MFDSAUtil
.GetTimestamp() - t > 30)
{
ret.HasError =
true
;
ret.ErrorMsg =
"请求无效"
;
return
ret;
}
//验证签名
string
signServer =
MFEncryptUtil
.Md5(
string
.Format(
"{0}:{1}"
, t, deviceUniqueIdentifier));
if
(!signServer.Equals(sign,
StringComparison
.CurrentCultureIgnoreCase))
{
ret.HasError =
true
;
ret.ErrorMsg =
"请求无效"
;
return
ret;
}
}
3.在向服务器请求的数据中,应该包含数据类型,用来告诉服务器需要对数据库进行怎样的操作。比如1001代表注册,1002代表登录……
string
userName = data[
"UserName"
].ToString();
string
pwd = data[
"Pwd"
].ToString();
string
channelId = data[
"ChannelId"
].ToString();
int
type =
Convert
.ToInt32(data[
"Type"
].ToString());
4.服务器将从数据库获取的信息经过封装传给客户端,这里需要定义一个返回数据的类,一般来说,里面都会包含一些基本的属性,比如:是否有错、错误信息、传递的信息等
public
class
CallBackArgs
:
EventArgs
{
///
<summary>
///
错误原因
///
</summary>
public
string
ErrorMsg;
///
<summary>
///
是否有错
///
</summary>
public
bool
HasError;
///
<summary>
///
json数据
///
</summary>
public
string
Data;
}
5.传输的形式我们一般采用json格式,在Web的MVC框架中我们如果返回一个对象,也会被自动转化为一个json传回客户端,所以我们客户端为了形成统一,也是用Json来进行传输,将需要的键值对封装在字典中转化为Json发给服务器,服务器再解json获取请求信息。
//设备号
dic[
"deviceUniqueIdentifier"
] =
DeviceUtil
.DeviceUniqueIdentifier;
dic[
"deviceModel"
] =
DeviceUtil
.DeviceModel;
long
t =
DeviceUtil
.CurrServerTime;
//签名
dic[
"sign"
] =
EncryptUtil
.Md5(
string
.Format(
"{0}:{1}"
, t,
DeviceUtil
.DeviceUniqueIdentifier));
//时间戳
dic[
"t"
] = t;
总结
在HTTP中,我们会用到POST或者GET方式,但是无论哪种方式,都会有安全隐患,比如频繁的POST攻击等等会使服务器瘫痪,那么我们要防止这种事情发生。时间戳和签名让我们将这样的风险降至最小,然后就是HTTP协议规定,让通讯更有效,一般我们会结合观察者模式,监听收到的消息,执行对应的方法,这样也容易分清层次,有利于封装和扩展。