Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.

Commit fda5172

Browse files
authored
Merge pull request #51 from lc6464/dev
完成基本用户账户及聊天功能
2 parents 4d51bad + a632207 commit fda5172

27 files changed

Lines changed: 1157 additions & 449 deletions

Common/Database.cs

Lines changed: 0 additions & 126 deletions
This file was deleted.

Controllers/LoginController.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,60 +6,63 @@ namespace SimpleWebChatApplication.Controllers;
66
public class LoginController : ControllerBase {
77
private readonly ILogger<LoginController> _logger;
88
private readonly IDataProvider _provider;
9-
private readonly ICheckingTools _tools;
10-
private readonly ISession Session;
9+
private readonly IGeneralTools _tools;
10+
private readonly IHttpConnectionInfo _info;
1111

12-
public LoginController(ILogger<LoginController> logger, IDataProvider provider, ICheckingTools tools) {
12+
public LoginController(ILogger<LoginController> logger, IDataProvider provider, IGeneralTools tools, IHttpConnectionInfo info) {
1313
_logger = logger;
1414
_provider = provider;
1515
_tools = tools;
16-
Session = HttpContext.Session;
16+
_info = info;
1717
}
1818

1919

2020
[HttpGet]
2121
[ResponseCache(CacheProfileName = "NoStore")]
2222
public Models.Login Get() => _tools.IsLogin(out var displayName)
23-
? new() { Success = true, Code = 0, Message = "已登录。", DisplayName = displayName }
24-
: new() { Success = false, Code = 3, Message = "未登录。" };
23+
? new() { Success = true, Code = 0, DisplayName = displayName }
24+
: new() { Success = false, Code = 3 };
2525

2626

2727
[HttpPost]
2828
[ResponseCache(CacheProfileName = "NoStore")]
29-
public Models.Login Post(string? account, string? password) {
29+
public Models.Login Post([FromForm] string? account, [FromForm] string? password) {
3030
if (_tools.IsLogin()) {
3131
return new() { Success = true, Code = 1, Message = "您已经登录过了。" };
3232
}
33-
if (account is null || password is null) {
33+
if (string.IsNullOrWhiteSpace(account) || string.IsNullOrWhiteSpace(password)) {
3434
return new() { Success = false, Code = 5, Message = "用户名或密码为空。" };
3535
}
3636
_ = Hubs.Cache.MemoryCache.TryGetValue($"TryLoginCount of {account}", out int count);
3737
if (count > 5) {
38-
_logger.LogWarning("用户 {} 尝试登录次数过多,最后一次 IP 地址为 {}。", account, HttpContext.Connection.RemoteIpAddress);
38+
_logger.LogWarning("Post: 用户 {} 尝试登录次数过多,最后一次 IP 地址为 {}。", account, _info.RemoteAddress);
3939
return new() { Success = false, Code = 7, Message = "尝试登录次数过多,请在30分钟后重试。" };
4040
}
41-
if (account.Length is < 4 or > 32 || !ICheckingTools.IsPasswordComplicated(password)) {
42-
_ = Hubs.Cache.Set($"TryLoginCount of {account}", count++, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
41+
if (account.Length is < 4 or > 32 || !IGeneralTools.IsPasswordComplicated(password)) {
42+
_ = Hubs.Cache.Set($"TryLoginCount of {account}", ++count, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
4343
return new() { Success = false, Code = 6, Message = "用户名或密码错误。" };
4444
}
45-
using var reader = _provider.GetUserReader(account);
45+
using var reader = _provider.GetUserReader(account, out var cmd);
4646
if (!reader.Read()) {
47-
_ = Hubs.Cache.Set($"TryLoginCount of {account}", count++, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
47+
_ = Hubs.Cache.Set($"TryLoginCount of {account}", ++count, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
4848
return new() { Success = false, Code = 6, Message = "用户名或密码错误。" };
4949
}
5050
var hash = new byte[64];
5151
_ = reader.GetBytes(3, 0, hash, 0, 64);
5252
var salt = new byte[16];
5353
_ = reader.GetBytes(4, 0, salt, 0, 16);
54-
if (!ICheckingTools.VerifyPassword(password, hash, salt)) {
55-
_ = Hubs.Cache.Set($"TryLoginCount of {account}", count++, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
54+
if (!IGeneralTools.VerifyPassword(password, hash, salt)) {
55+
_ = Hubs.Cache.Set($"TryLoginCount of {account}", ++count, TimeSpan.FromMinutes(30), TimeSpan.FromHours(2));
5656
return new() { Success = false, Code = 6, Message = "用户名或密码错误。" };
5757
}
5858
Hubs.Cache.MemoryCache.Remove($"TryLoginCount of {account}");
59-
Session.SetString("Name", account);
60-
Session.SetString("Nick", reader.GetString(2));
61-
Session.Set("Hash", hash);
62-
Session.Set("Salt", salt);
63-
return new() { Success = true, Code = 0, Message = "登录成功!" };
59+
HttpContext.Session.SetString("Name", account);
60+
HttpContext.Session.SetString("Nick", reader.GetString(2));
61+
HttpContext.Session.Set("Hash", hash);
62+
HttpContext.Session.Set("Salt", salt);
63+
cmd.Dispose();
64+
_logger.LogDebug("Post: 用户 {} 于 {} 登录成功。", account, _info.RemoteAddress);
65+
return new() { Success = true, Code = 0 };
66+
6467
}
6568
}

Controllers/Models/Hello.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public readonly struct Hello {
1010

1111
public Hello(IHttpConnectionInfo info) => IP = new(info);
1212

13-
public readonly DateTime Time => DateTime.Now;
13+
public readonly DateTime Time => DateTime.UtcNow;
1414

1515
public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute))!).Copyright;
1616

Controllers/Models/Register.cs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using System.Text.Json.Serialization;
2+
using SimpleWebChatApplication.Services;
3+
4+
namespace SimpleWebChatApplication.Controllers.Models;
5+
6+
/// <summary>
7+
/// RegisterController 用户 Post 方法的响应。
8+
/// </summary>
9+
public readonly struct RegisterUserPostResponse {
10+
public bool Success { get; init; }
11+
public int Code { get; init; }
12+
public string? Message { get; init; }
13+
public string? Data { get; init; }
14+
}
15+
16+
17+
/// <summary>
18+
/// RegisterController 用户 Post 方法用户数据序列化模板。
19+
/// </summary>
20+
public readonly struct RegisterUserPostJsonSerializeTemplate {
21+
public RegisterUserPostJsonSerializeTemplate() => HMACKey = IGeneralTools.GenerateRandomData(16).ToArray();
22+
23+
[JsonPropertyName("a")]
24+
public string? Account { get; init; }
25+
26+
[JsonPropertyName("h")]
27+
public byte[]? PasswordHash { get; init; }
28+
29+
[JsonPropertyName("s")]
30+
public byte[]? PasswordSalt { get; init; }
31+
32+
[JsonPropertyName("k")]
33+
public byte[] HMACKey { get; init; }
34+
}
35+
36+
37+
/// <summary>
38+
/// RegisterController 管理员 Get 方法的响应。
39+
/// </summary>
40+
public readonly struct RegisterGetResponse {
41+
public bool Success { get; init; }
42+
public int Code { get; init; }
43+
public string? Message { get; init; }
44+
public RegisterGetResponseUserData? Data { get; init; }
45+
}
46+
47+
48+
/// <summary>
49+
/// RegisterController 管理员 Get 方法用户数据反序列化模板。
50+
/// </summary>
51+
public readonly struct RegisterGetJsonDeserializeTemplate {
52+
[JsonPropertyName("a")]
53+
public string? Account { get; init; }
54+
55+
[JsonPropertyName("h")]
56+
public byte[]? PasswordHash { get; init; }
57+
58+
[JsonPropertyName("s")]
59+
public byte[]? PasswordSalt { get; init; }
60+
61+
[JsonPropertyName("k")]
62+
public byte[]? HMACKey { get; init; }
63+
}
64+
65+
66+
/// <summary>
67+
/// RegisterController 管理员 Get 方法的响应中的用户数据。
68+
/// </summary>
69+
public readonly struct RegisterGetResponseUserData {
70+
public RegisterGetResponseUserData(RegisterGetJsonDeserializeTemplate userData, long timestamp) {
71+
Account = userData.Account;
72+
PasswordHash = userData.PasswordHash;
73+
PasswordSalt = userData.PasswordSalt;
74+
Timestamp = timestamp;
75+
}
76+
77+
public string? Account { get; init; }
78+
79+
public byte[]? PasswordHash { get; init; }
80+
81+
public byte[]? PasswordSalt { get; init; }
82+
83+
public long? Timestamp { get; init; }
84+
}
85+
86+
87+
/// <summary>
88+
/// RegisterController Import 方法的响应中的数据。
89+
/// </summary>
90+
public readonly struct RegisterImportResponse {
91+
public bool Success { get; init; }
92+
public int Code { get; init; }
93+
public string? Message { get; init; }
94+
public RegisterImportResponseData? Data { get; init; }
95+
}
96+
97+
/// <summary>
98+
/// RegisterController Import 方法的响应。
99+
/// </summary>
100+
public readonly struct RegisterImportResponseData {
101+
public RegisterImportResponseData(RegisterGetResponseUserData userData, long id, long importTime) {
102+
UserID = id;
103+
UserName = userData.Account!;
104+
RegisterTime = (long)userData.Timestamp!;
105+
ImportTime = importTime;
106+
}
107+
108+
public long UserID { get; init; }
109+
110+
public string UserName { get; init; }
111+
112+
public long RegisterTime { get; init; }
113+
114+
public long ImportTime { get; init; }
115+
}

0 commit comments

Comments
 (0)