服务器注册函数

在SimpleServer项目的Business文件夹内新建UserManagerServerEnum,并将MySql项目依赖过来

ServerEnum储存注册的结果枚举、登录结果的枚举、注册类型的枚举和登录类型的枚举,和ProtocolEnum差不多,这个文件和客户端通用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace SimpleServer.Business
{
public enum RegisterType
{
Phone,//手机号码注册
Mail,//邮箱注册
QQ,
WX
}
public enum LoginType
{
Phone,
Mail,
WX,
QQ,
Token
}
public enum RegisterResult
{
Success,
Failed,
AlreadyExist,
WrongCode,//手机验证码错误
Outdated,//验证码超时
Forbidden,//账号被封禁
}
public enum LoginResult
{
Success,
Failed,
WrongPwd,//密码错误
UserNotExist,
TimeoutToken//服务端的Token过期
}
}

UserManager编写具体注册的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using ServerBase;
using MySql;
using MySql.MySQLData;

namespace SimpleServer.Business
{
public class UserManager : SingletonPattern<UserManager>
{
/// <summary>
/// 注册新用户
/// </summary>
/// <param name="type">注册方式</param>
/// <param name="username">用户名</param>
/// <param name="password">密码</param>
/// <param name="token">用户token</param>
/// <returns>注册结果</returns>
public RegisterResult Register(RegisterType type, string? username, string? password,out string token)
{
token = "";
try
{
int? count = MySqlMgr.Instance.SqlSugarDB?.Queryable<User>().Where(it => it.Username == username).Count();
if(count > 0)
{
return RegisterResult.AlreadyExist;
}
User user = new User();
switch (type)
{
case RegisterType.Phone:
{
//检验验证码1.是否超时 2.是否正确
//...
user.Logintype = LoginType.Phone.ToString();
break;
}
case RegisterType.Mail:
{
user.Logintype = LoginType.Mail.ToString();
break;
}
}
user.Username = username;
user.Password = password;
user.Token = Guid.NewGuid().ToString();
user.Logindate = DateTime.Now;
token = user.Token;
MySqlMgr.Instance.SqlSugarDB?.Insertable(user).ExecuteCommand();
return RegisterResult.Success;
}
catch (Exception ex)
{
Debug.LogError("注册失败" + ex.ToString());
return RegisterResult.Failed;
}
}
}
}

正常情况下,Register函数还需要另外一个参数,这个参数表示邮箱或手机的验证码。Register函数内部要有检验验证码的逻辑。

验证码流程:

我们需要先准备一个发送验证码的协议,客户端输入自己的手机号,点击“获取验证码”后,使用这个协议将自己的手机号发送给服务端,服务端得到获取验证码的请求后,自己生成验证码,把这个验证码和申请时间先存储到当前客户端对应的数据库中,然后使用阿里云或腾讯云的SMS服务将验证码使用短信的方式发送给客户端,客户端获取到短信后再将验证码发送到服务器,进入注册流程。

如果想要自动登录,注册时服务器需要对当前客户端生成一个token(一种随机字符串),并存储在数据库中,并把token返回给客户端,客户端加密后保存在客户端本地。下次登录时,客户端将token(作为密码)发送给服务器,服务器验证成功后自动登录。如果使用QQ微信登录,可以将QQ微信生成的token存储在服务器数据库中。如果使用自定义token,客户端每次登录时服务器需要变更token并返回给客户端更新token

如果使用QQ、微信登录,服务器并不会存储用户名和密码,而是存储相应平台的unionid。

服务器登录函数

UserManager编写具体登录的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/// <summary>
/// 用户登录
/// </summary>
/// <param name="username">用户名</param>
/// <param name="password">密码</param>
/// <returns>登录结果</returns>
public LoginResult Login(LoginType loginType, string? username, string? password,out int userId,out string token)
{
userId = 0;
token = "";
try
{
User? user = null;
switch (loginType)
{
case LoginType.Phone:
case LoginType.Mail:
user = MySqlMgr.Instance.SqlSugarDB?.Queryable<User>().Where(it => it.Username == username).Single();
break;
case LoginType.WX:
case LoginType.QQ:
//如果是QQ微信,再User类中要有unionid字段,在这里判断
//.Where(it => it.Unionid == username)
break;
case LoginType.Token:
user = MySqlMgr.Instance.SqlSugarDB?.Queryable<User>().Where(it => it.Username == username).Single();
break;
}
if (user == null)
{
//QQ微信是首次登录的话相当于注册
if(loginType == LoginType.QQ || loginType == LoginType.WX)
{
//在数据库注册QQ微信
user = new User();
user.Username = username;
user.Password = password;//注意,这里可能为空
user.Logintype = loginType.ToString();
user.Token = Guid.NewGuid().ToString();
user.Logindate = DateTime.Now;
//储存Unionid = username;
token = user.Token;
userId = (int)(MySqlMgr.Instance.SqlSugarDB?.Insertable(user).ExecuteReturnIdentity());
return LoginResult.Success;
}
else
{
return LoginResult.UserNotExist;
}
}
else
{
if(loginType != LoginType.Token)
{
if(loginType == LoginType.Phone)
{
if(user.Password != password)
return LoginResult.WrongPwd;

}
else if(loginType == LoginType.Mail)
{
if(user.Password != password)
return LoginResult.WrongPwd;
}
}
else
{
if (user.Token != password)
{
return LoginResult.TimeoutToken;
}
}
user.Token = Guid.NewGuid().ToString();
user.Logindate = DateTime.Now;
token = user.Token;
MySqlMgr.Instance.SqlSugarDB?.Updateable(user).ExecuteCommand();
userId = user.Id;
return LoginResult.Success;
}
}
catch (Exception ex)
{
Debug.LogError("登录失败:" + ex.ToString());
return LoginResult.Failed;
}
}
/// <summary>
/// 获取用户
/// </summary>
/// <param name="id">用户Id</param>
/// <returns>用户</returns>
public User GetUserById(int id)
{
try
{
return MySqlMgr.Instance.SqlSugarDB!.Queryable<User>().InSingle(id);
}
catch (Exception ex)
{
Debug.LogError("获取用户失败:" + ex);
throw;
}
}

正常情况下,Login函数还返回了客户端的userId,方便查找数据库

如果是使用QQ,WX登录,Login函数传入的username是unionid,password没有值。