diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs index 4123f7e..ddfaa14 100644 --- a/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs +++ b/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace MiAssessment.Core.Services; /// -/// ��֤����ʵ�� +/// 认证服务实现 /// public class AuthService : IAuthService { @@ -30,7 +30,7 @@ public class AuthService : IAuthService private const string SmsCodeKeyPrefix = "sms:code:"; private const int DebounceSeconds = 3; - // Refresh Token ���� + // Refresh Token 长度 private const int RefreshTokenLength = 64; public AuthService( @@ -57,44 +57,44 @@ public class AuthService : IAuthService /// - /// ΢��С�����¼ + /// 微信小程序登录 /// Requirements: 1.1-1.8 /// public async Task WechatMiniProgramLoginAsync(string code, int? pid, string? clickId, string? phoneCode = null) { - _logger.LogInformation("[AuthService] ΢�ŵ�¼��ʼ��code={Code}, pid={Pid}, hasPhoneCode={HasPhoneCode}", code, pid, !string.IsNullOrWhiteSpace(phoneCode)); + _logger.LogInformation("[AuthService] 微信登录开始,code={Code}, pid={Pid}, hasPhoneCode={HasPhoneCode}", code, pid, !string.IsNullOrWhiteSpace(phoneCode)); if (string.IsNullOrWhiteSpace(code)) { - _logger.LogWarning("[AuthService] ΢�ŵ�¼ʧ�ܣ�codeΪ��"); + _logger.LogWarning("[AuthService] 微信登录失败,code为空"); return new LoginResult { Success = false, - ErrorMessage = "��Ȩcode����Ϊ��" + ErrorMessage = "授权code不能为空" }; } try { - // 1.6 �������� - 3���ڲ������ظ���¼ + // 1.6 防抖处理 - 3秒内不允许重复登录 var debounceKey = $"{LoginDebounceKeyPrefix}wechat:{code}"; - _logger.LogInformation("[AuthService] ��������: {Key}", debounceKey); + _logger.LogInformation("[AuthService] 防抖检查: {Key}", debounceKey); var lockAcquired = await _redisService.TryAcquireLockAsync(debounceKey, "1", TimeSpan.FromSeconds(DebounceSeconds)); if (!lockAcquired) { - _logger.LogWarning("[AuthService] �����������ܾ��ظ���¼����: {Code}", code); + _logger.LogWarning("[AuthService] 防抖处理:拒绝重复登录请求: {Code}", code); return new LoginResult { Success = false, - ErrorMessage = "����Ƶ����¼" + ErrorMessage = "请勿频繁登录" }; } - _logger.LogInformation("[AuthService] ��������ȡ�ɹ�"); + _logger.LogInformation("[AuthService] 防抖锁获取成功"); - // 1.1 ����΢��API��ȡopenid��unionid - _logger.LogInformation("[AuthService] ��ʼ����΢��API��ȡopenid..."); + // 1.1 调用微信API获取openid和unionid + _logger.LogInformation("[AuthService] 开始调用微信API获取openid..."); var wechatResult = await _wechatService.GetOpenIdAsync(code); - _logger.LogInformation("[AuthService] ΢��API������ɣ�Success={Success}, OpenId={OpenId}, UnionId={UnionId}, Error={Error}", + _logger.LogInformation("[AuthService] 微信API调用完成:Success={Success}, OpenId={OpenId}, UnionId={UnionId}, Error={Error}", wechatResult.Success, wechatResult.OpenId ?? "null", wechatResult.UnionId ?? "null", @@ -102,30 +102,30 @@ public class AuthService : IAuthService if (!wechatResult.Success) { - _logger.LogWarning("[AuthService] ΢��API����ʧ��: {Error}", wechatResult.ErrorMessage); + _logger.LogWarning("[AuthService] 微信API调用失败: {Error}", wechatResult.ErrorMessage); return new LoginResult { Success = false, - ErrorMessage = wechatResult.ErrorMessage ?? "��¼ʧ�ܣ����Ժ�����" + ErrorMessage = wechatResult.ErrorMessage ?? "登录失败,请稍后重试" }; } var openId = wechatResult.OpenId!; var unionId = wechatResult.UnionId; - // 1.2 �����û� - ����ͨ��unionid���ң����ͨ��openid���� + // 1.2 查找用户 - 优先通过unionid查找,再通过openid查找 User? user = null; if (!string.IsNullOrWhiteSpace(unionId)) { - _logger.LogInformation("[AuthService] ����ͨ��unionid�����û�: {UnionId}", unionId); + _logger.LogInformation("[AuthService] 尝试通过unionid查找用户: {UnionId}", unionId); user = await _userService.GetUserByUnionIdAsync(unionId); - _logger.LogInformation("[AuthService] unionid���ҽ��: {Found}", user != null ? $"�ҵ��û�ID={user.Id}" : "δ�ҵ�"); + _logger.LogInformation("[AuthService] unionid查找结果: {Found}", user != null ? $"找到用户ID={user.Id}" : "未找到"); } if (user == null) { - _logger.LogInformation("[AuthService] ����ͨ��openid�����û�: {OpenId}", openId); + _logger.LogInformation("[AuthService] 尝试通过openid查找用户: {OpenId}", openId); user = await _userService.GetUserByOpenIdAsync(openId); - _logger.LogInformation("[AuthService] openid���ҽ��: {Found}", user != null ? $"�ҵ��û�ID={user.Id}" : "δ�ҵ�"); + _logger.LogInformation("[AuthService] openid查找结果: {Found}", user != null ? $"找到用户ID={user.Id}" : "未找到"); } if (user == null) @@ -189,36 +189,42 @@ public class AuthService : IAuthService } } - // 1.5 ����˫ Token��Access Token + Refresh Token�� - _logger.LogInformation("[AuthService] ��ʼ����˫ Token: UserId={UserId}", user.Id); + // 1.5 生成双 Token(Access Token + Refresh Token) + _logger.LogInformation("[AuthService] 开始生成双 Token: UserId={UserId}", user.Id); var loginResponse = await GenerateLoginResponseAsync(user, null); - _logger.LogInformation("[AuthService] ˫ Token ���ɳɹ���AccessToken����={Length}", loginResponse.AccessToken?.Length ?? 0); - _logger.LogInformation("[AuthService] ΢�ŵ�¼�ɹ�: UserId={UserId}", user.Id); + // 更新最后登录时间 + user.LastLoginTime = DateTime.Now; + _dbContext.Users.Update(user); + await _dbContext.SaveChangesAsync(); + + _logger.LogInformation("[AuthService] 双 Token 生成成功,AccessToken长度={Length}", loginResponse.AccessToken?.Length ?? 0); + + _logger.LogInformation("[AuthService] 微信登录成功: UserId={UserId}", user.Id); return new LoginResult { Success = true, - Token = loginResponse.AccessToken, // ���ݾɰ� + Token = loginResponse.AccessToken, // 兼容旧版 UserId = user.Id, LoginResponse = loginResponse }; } catch (Exception ex) { - _logger.LogError(ex, "[AuthService] ΢�ŵ�¼�쳣: code={Code}, Message={Message}, StackTrace={StackTrace}", + _logger.LogError(ex, "[AuthService] 微信登录异常: code={Code}, Message={Message}, StackTrace={StackTrace}", code, ex.Message, ex.StackTrace); return new LoginResult { Success = false, - ErrorMessage = "������ϣ����Ժ�����" + ErrorMessage = "服务器异常,请稍后重试" }; } } /// - /// �ֻ�����֤���¼ + /// 手机号验证码登录 /// Requirements: 2.1-2.7 /// public async Task MobileLoginAsync(string mobile, string code, int? pid, string? clickId) @@ -228,7 +234,7 @@ public class AuthService : IAuthService return new LoginResult { Success = false, - ErrorMessage = "�ֻ��Ų���Ϊ��" + ErrorMessage = "手机号不能为空" }; } @@ -237,13 +243,13 @@ public class AuthService : IAuthService return new LoginResult { Success = false, - ErrorMessage = "��֤�벻��Ϊ��" + ErrorMessage = "验证码不能为空" }; } try { - // 2.6 �������� - 3���ڲ������ظ���¼ + // 2.6 防抖处理 - 3秒内不允许重复登录 var debounceKey = $"{LoginDebounceKeyPrefix}mobile:{mobile}"; var lockAcquired = await _redisService.TryAcquireLockAsync(debounceKey, "1", TimeSpan.FromSeconds(DebounceSeconds)); if (!lockAcquired) @@ -252,11 +258,11 @@ public class AuthService : IAuthService return new LoginResult { Success = false, - ErrorMessage = "����Ƶ����¼" + ErrorMessage = "请勿频繁登录" }; } - // 2.1 ��Redis��ȡ����֤��֤�� + // 2.1 从Redis获取短信验证码验证 var smsCodeKey = $"{SmsCodeKeyPrefix}{mobile}"; var storedCode = await _redisService.GetStringAsync(smsCodeKey); @@ -266,19 +272,19 @@ public class AuthService : IAuthService return new LoginResult { Success = false, - ErrorMessage = "��֤�����" + ErrorMessage = "验证码错误" }; } - // 2.2 ��֤����֤ͨ����ɾ��Redis�е���֤�� + // 2.2 验证码验证通过,删除Redis中的验证码 await _redisService.DeleteAsync(smsCodeKey); - // �����û� + // 查找用户 var user = await _userService.GetUserByMobileAsync(mobile); if (user == null) { - // 2.3 �û������ڣ��������û� + // 2.3 用户不存在,创建新用户 var createDto = new CreateUserDto { Mobile = mobile, @@ -291,15 +297,20 @@ public class AuthService : IAuthService _logger.LogInformation("New user created via mobile login: UserId={UserId}, Mobile={Mobile}", user.Id, MaskMobile(mobile)); } - // 2.4 ����˫ Token��Access Token + Refresh Token�� + // 2.4 生成双 Token(Access Token + Refresh Token) var loginResponse = await GenerateLoginResponseAsync(user, null); + // 更新最后登录时间 + user.LastLoginTime = DateTime.Now; + _dbContext.Users.Update(user); + await _dbContext.SaveChangesAsync(); + _logger.LogInformation("Mobile login successful: UserId={UserId}", user.Id); return new LoginResult { Success = true, - Token = loginResponse.AccessToken, // ���ݾɰ� + Token = loginResponse.AccessToken, // 兼容旧版 UserId = user.Id, LoginResponse = loginResponse }; @@ -310,58 +321,58 @@ public class AuthService : IAuthService return new LoginResult { Success = false, - ErrorMessage = "������ϣ����Ժ�����" + ErrorMessage = "服务器异常,请稍后重试" }; } } /// - /// ��֤����ֻ��� + /// 验证码绑定手机号 /// Requirements: 5.1-5.5 /// public async Task BindMobileAsync(long userId, string mobile, string code) { if (string.IsNullOrWhiteSpace(mobile)) { - throw new ArgumentException("�ֻ��Ų���Ϊ��", nameof(mobile)); + throw new ArgumentException("手机号不能为空", nameof(mobile)); } if (string.IsNullOrWhiteSpace(code)) { - throw new ArgumentException("��֤�벻��Ϊ��", nameof(code)); + throw new ArgumentException("验证码不能为空", nameof(code)); } - // 5.1 ��֤������֤�� + // 5.1 验证短信验证码 var smsCodeKey = $"{SmsCodeKeyPrefix}{mobile}"; var storedCode = await _redisService.GetStringAsync(smsCodeKey); if (string.IsNullOrWhiteSpace(storedCode) || storedCode != code) { _logger.LogWarning("SMS code verification failed for bind mobile: UserId={UserId}, Mobile={Mobile}", userId, MaskMobile(mobile)); - throw new InvalidOperationException("��֤�����"); + throw new InvalidOperationException("验证码错误"); } - // ��֤����֤ͨ����ɾ�� + // 验证码验证通过,删除 await _redisService.DeleteAsync(smsCodeKey); - // ��ȡ��ǰ�û� + // 获取当前用户 var currentUser = await _userService.GetUserByIdAsync(userId); if (currentUser == null) { - throw new InvalidOperationException("�û�������"); + throw new InvalidOperationException("用户不存在"); } - // ����ֻ����Ƿ��ѱ������û��� + // 检查手机号是否已被其他用户绑定 var existingUser = await _userService.GetUserByMobileAsync(mobile); if (existingUser != null && existingUser.Id != userId) { - // 5.2 �ֻ����ѱ������û��󶨣���Ҫ�ϲ��˻� + // 5.2 手机号已被其他用户绑定,需要合并账户 return await MergeAccountsAsync(currentUser, existingUser); } - // 5.4 �ֻ���δ���󶨣�ֱ�Ӹ��µ�ǰ�û����ֻ��� + // 5.4 手机号未被绑定,直接更新当前用户的手机号 await _userService.UpdateUserAsync(userId, new UpdateUserDto { Mobile = mobile }); _logger.LogInformation("Mobile bound successfully: UserId={UserId}, Mobile={Mobile}", userId, MaskMobile(mobile)); @@ -369,43 +380,43 @@ public class AuthService : IAuthService } /// - /// ΢����Ȩ���ֻ��� + /// 微信授权绑定手机号 /// Requirements: 5.1-5.5 /// public async Task WechatBindMobileAsync(long userId, string wechatCode) { if (string.IsNullOrWhiteSpace(wechatCode)) { - throw new ArgumentException("΢����Ȩcode����Ϊ��", nameof(wechatCode)); + throw new ArgumentException("微信授权code不能为空", nameof(wechatCode)); } - // ����΢��API��ȡ�ֻ��� + // 调用微信API获取手机号 var mobileResult = await _wechatService.GetMobileAsync(wechatCode); if (!mobileResult.Success || string.IsNullOrWhiteSpace(mobileResult.Mobile)) { _logger.LogWarning("WeChat get mobile failed: UserId={UserId}, Error={Error}", userId, mobileResult.ErrorMessage); - throw new InvalidOperationException(mobileResult.ErrorMessage ?? "��ȡ�ֻ���ʧ��"); + throw new InvalidOperationException(mobileResult.ErrorMessage ?? "获取手机号失败"); } var mobile = mobileResult.Mobile; - // ��ȡ��ǰ�û� + // 获取当前用户 var currentUser = await _userService.GetUserByIdAsync(userId); if (currentUser == null) { - throw new InvalidOperationException("�û�������"); + throw new InvalidOperationException("用户不存在"); } - // ����ֻ����Ƿ��ѱ������û��� + // 检查手机号是否已被其他用户绑定 var existingUser = await _userService.GetUserByMobileAsync(mobile); if (existingUser != null && existingUser.Id != userId) { - // 5.2 �ֻ����ѱ������û��󶨣���Ҫ�ϲ��˻� + // 5.2 手机号已被其他用户绑定,需要合并账户 return await MergeAccountsAsync(currentUser, existingUser); } - // 5.4 �ֻ���δ���󶨣�ֱ�Ӹ��µ�ǰ�û����ֻ��� + // 5.4 手机号未被绑定,直接更新当前用户的手机号 await _userService.UpdateUserAsync(userId, new UpdateUserDto { Mobile = mobile }); _logger.LogInformation("Mobile bound via WeChat successfully: UserId={UserId}, Mobile={Mobile}", userId, MaskMobile(mobile)); @@ -414,7 +425,7 @@ public class AuthService : IAuthService /// - /// ��¼��¼��Ϣ + /// 记录登录信息 /// Requirements: 6.1, 6.3, 6.4 /// public async Task RecordLoginAsync(long userId, string? device, string? deviceInfo) @@ -422,17 +433,17 @@ public class AuthService : IAuthService var user = await _userService.GetUserByIdAsync(userId); if (user == null) { - throw new InvalidOperationException("�û�������"); + throw new InvalidOperationException("用户不存在"); } try { - // ��ȡ�ͻ���IP������ʹ�ÿ��ַ�����Ϊռλ����ʵ��IPӦ��Controller���룩 + // 获取客户端IP(这里使用空字符串作为占位,实际IP应由Controller传入) var clientIp = deviceInfo ?? string.Empty; var now = DateTime.Now; - // 6.1 ��¼��¼��־ + // 6.1 记录登录日志 var loginLog = new UserLoginLog { UserId = userId, @@ -446,7 +457,7 @@ public class AuthService : IAuthService await _dbContext.UserLoginLogs.AddAsync(loginLog); - // �����û�����¼ʱ�� + // 更新用户最后登录时间 user.LastLoginTime = now; user.LastLoginIp = clientIp; _dbContext.Users.Update(user); @@ -455,7 +466,7 @@ public class AuthService : IAuthService _logger.LogInformation("Login recorded: UserId={UserId}, Device={Device}, IP={IP}", userId, device, clientIp); - // 6.4 �����û���uid���dzƺ�ͷ�� + // 6.4 返回用户的uid、昵称和头像 return new RecordLoginResponse { Uid = user.Uid, @@ -471,33 +482,33 @@ public class AuthService : IAuthService } /// - /// H5���ֻ��ţ�������֤�룩 + /// H5绑定手机号(无需验证码) /// Requirements: 13.1 /// public async Task BindMobileH5Async(long userId, string mobile) { if (string.IsNullOrWhiteSpace(mobile)) { - throw new ArgumentException("�ֻ��Ų���Ϊ��", nameof(mobile)); + throw new ArgumentException("手机号不能为空", nameof(mobile)); } - // ��ȡ��ǰ�û� + // 获取当前用户 var currentUser = await _userService.GetUserByIdAsync(userId); if (currentUser == null) { - throw new InvalidOperationException("�û�������"); + throw new InvalidOperationException("用户不存在"); } - // ����ֻ����Ƿ��ѱ������û��� + // 检查手机号是否已被其他用户绑定 var existingUser = await _userService.GetUserByMobileAsync(mobile); if (existingUser != null && existingUser.Id != userId) { - // �ֻ����ѱ������û��󶨣���Ҫ�ϲ��˻� + // 手机号已被其他用户绑定,需要合并账户 return await MergeAccountsAsync(currentUser, existingUser); } - // �ֻ���δ���󶨣�ֱ�Ӹ��µ�ǰ�û����ֻ��� + // 手机号未被绑定,直接更新当前用户的手机号 await _userService.UpdateUserAsync(userId, new UpdateUserDto { Mobile = mobile }); _logger.LogInformation("H5 Mobile bound successfully: UserId={UserId}, Mobile={Mobile}", userId, MaskMobile(mobile)); @@ -505,7 +516,7 @@ public class AuthService : IAuthService } /// - /// �˺�ע�� + /// 账号注销 /// Requirements: 7.1-7.3 /// public async Task LogOffAsync(long userId, int type) @@ -513,23 +524,23 @@ public class AuthService : IAuthService var user = await _userService.GetUserByIdAsync(userId); if (user == null) { - throw new InvalidOperationException("�û�������"); + throw new InvalidOperationException("用户不存在"); } try { - // 7.1 ��¼ע��������־ - var action = type == 0 ? "ע���˺�" : "ȡ��ע��"; + // 7.1 记录注销操作日志 + var action = type == 0 ? "注销账号" : "取消注销"; _logger.LogInformation("User log off request: UserId={UserId}, Type={Type}, Action={Action}", userId, type, action); - // ����������Ӹ����ע���߼������磺 - // - ���û�״̬����Ϊ��ע�� - // - �����û���صĻ��� - // - ����֪ͨ�� + // 这里可以添加更多的注销逻辑,比如: + // - 将用户状态设置为已注销 + // - 清除用户相关的缓存 + // - 发送通知等 if (type == 0) { - // ע���˺� - ���������û�״̬Ϊ���� + // 注销账号 - 软删除,设置用户状态为禁用 user.Status = 0; _dbContext.Users.Update(user); await _dbContext.SaveChangesAsync(); @@ -537,14 +548,14 @@ public class AuthService : IAuthService } else if (type == 1) { - // ȡ��ע�� - �ָ��û�״̬ + // 取消注销 - 恢复用户状态 user.Status = 1; _dbContext.Users.Update(user); await _dbContext.SaveChangesAsync(); _logger.LogInformation("User account reactivated: UserId={UserId}", userId); } - // 7.2 ����ע���ɹ�����Ϣ��ͨ�����׳��쳣����ʾ�ɹ��� + // 7.2 返回注销成功的信息(通过不抛出异常来表示成功) } catch (Exception ex) { @@ -557,24 +568,24 @@ public class AuthService : IAuthService #region Refresh Token Methods /// - /// ���� Refresh Token ���洢�����ݿ� + /// 生成 Refresh Token 并存储到数据库 /// Requirements: 1.4, 1.5, 4.1 /// - /// �û�ID - /// �ͻ��� IP ��ַ - /// ���ɵ� Refresh Token ���� + /// 用户ID + /// 客户端 IP 地址 + /// 生成的 Refresh Token 字符串 private async Task GenerateRefreshTokenAsync(long userId, string? ipAddress) { - // ������� Refresh Token + // 生成随机 Refresh Token var refreshToken = GenerateSecureRandomString(RefreshTokenLength); - // ���� SHA256 ��ϣֵ���ڴ洢 + // 计算 SHA256 哈希值用于存储 var tokenHash = ComputeSha256Hash(refreshToken); - // �������ʱ�䣨7�죩 + // 设置过期时间(7天) var expiresAt = DateTime.Now.AddDays(_jwtSettings.RefreshTokenExpirationDays); - // �������ݿ��¼ + // 保存数据库记录 var userRefreshToken = new UserRefreshToken { UserId = userId, @@ -593,21 +604,21 @@ public class AuthService : IAuthService } /// - /// ���ɵ�¼��Ӧ������˫ Token�� + /// 生成登录响应(包含双 Token) /// Requirements: 1.1, 1.2, 1.3, 1.4, 1.5 /// - /// �û�ʵ�� - /// �ͻ��� IP ��ַ - /// ��¼��Ӧ + /// 用户实体 + /// 客户端 IP 地址 + /// 登录响应 private async Task GenerateLoginResponseAsync(User user, string? ipAddress) { - // ���� Access Token (JWT) + // 生成 Access Token (JWT) var accessToken = _jwtService.GenerateToken(user); - // ���� Refresh Token ���洢 + // 生成 Refresh Token 并存储 var refreshToken = await GenerateRefreshTokenAsync(user.Id, ipAddress); - // ���� Access Token ����ʱ�䣨�룩 + // 计算 Access Token 过期时间(秒) var expiresIn = _jwtSettings.ExpirationMinutes * 60; return new LoginResponse @@ -620,7 +631,7 @@ public class AuthService : IAuthService } /// - /// ˢ�� Token + /// 刷新 Token /// Requirements: 2.1-2.6 /// public async Task RefreshTokenAsync(string refreshToken, string? ipAddress) @@ -628,15 +639,15 @@ public class AuthService : IAuthService if (string.IsNullOrWhiteSpace(refreshToken)) { _logger.LogWarning("Refresh token is empty"); - return RefreshTokenResult.Fail("ˢ�����Ʋ���Ϊ��"); + return RefreshTokenResult.Fail("刷新令牌不能为空"); } try { - // ���� Token ��ϣֵ + // 计算 Token 哈希值 var tokenHash = ComputeSha256Hash(refreshToken); - // ���� Token ��¼ + // 查找 Token 记录 var storedToken = await _dbContext.UserRefreshTokens .Include(t => t.User) .FirstOrDefaultAsync(t => t.TokenHash == tokenHash); @@ -644,47 +655,47 @@ public class AuthService : IAuthService if (storedToken == null) { _logger.LogWarning("Refresh token not found: {TokenHash}", tokenHash.Substring(0, 8) + "..."); - return RefreshTokenResult.Fail("��Ч��ˢ������"); + return RefreshTokenResult.Fail("无效的刷新令牌"); } - // ����Ƿ��ѹ��� + // 检查是否已过期 if (storedToken.IsExpired) { _logger.LogWarning("Refresh token expired for user {UserId}", storedToken.UserId); - return RefreshTokenResult.Fail("ˢ�������ѹ���"); + return RefreshTokenResult.Fail("刷新令牌已过期"); } - // ����Ƿ��ѳ��� + // 检查是否已撤销 if (storedToken.IsRevoked) { _logger.LogWarning("Refresh token revoked for user {UserId}", storedToken.UserId); - return RefreshTokenResult.Fail("ˢ��������ʧЧ"); + return RefreshTokenResult.Fail("刷新令牌已失效"); } - // ����û��Ƿ��������Ч + // 检查用户是否存在且有效 var user = storedToken.User; if (user == null) { _logger.LogWarning("User not found for refresh token"); - return RefreshTokenResult.Fail("�û�������"); + return RefreshTokenResult.Fail("用户不存在"); } if (user.Status == 0) { _logger.LogWarning("User {UserId} is disabled", user.Id); - return RefreshTokenResult.Fail("�˺��ѱ�����"); + return RefreshTokenResult.Fail("账号已被禁用"); } - // Token �ֻ��������µ� Refresh Token + // Token 轮换:生成新的 Refresh Token var newRefreshToken = GenerateSecureRandomString(RefreshTokenLength); var newTokenHash = ComputeSha256Hash(newRefreshToken); - // ������ Token ����¼������ϵ + // 标记旧 Token 的记录和替换关系 storedToken.RevokedAt = DateTime.Now; storedToken.RevokedByIp = ipAddress; storedToken.ReplacedByToken = newTokenHash; - // �����µ� Token ��¼ + // 保存新的 Token 记录 var newUserRefreshToken = new UserRefreshToken { UserId = user.Id, @@ -697,7 +708,7 @@ public class AuthService : IAuthService await _dbContext.UserRefreshTokens.AddAsync(newUserRefreshToken); await _dbContext.SaveChangesAsync(); - // �����µ� Access Token + // 生成新的 Access Token var accessToken = _jwtService.GenerateToken(user); var expiresIn = _jwtSettings.ExpirationMinutes * 60; @@ -714,12 +725,12 @@ public class AuthService : IAuthService catch (Exception ex) { _logger.LogError(ex, "Error refreshing token"); - return RefreshTokenResult.Fail("ˢ������ʧ�ܣ����Ժ�����"); + return RefreshTokenResult.Fail("刷新令牌失败,请稍后重试"); } } /// - /// ���� Token + /// 撤销 Token /// Requirements: 4.4 /// public async Task RevokeTokenAsync(string refreshToken, string? ipAddress) @@ -732,10 +743,10 @@ public class AuthService : IAuthService try { - // ���� Token ��ϣֵ + // 计算 Token 哈希值 var tokenHash = ComputeSha256Hash(refreshToken); - // ���� Token ��¼ + // 查找 Token 记录 var storedToken = await _dbContext.UserRefreshTokens .FirstOrDefaultAsync(t => t.TokenHash == tokenHash); @@ -745,14 +756,14 @@ public class AuthService : IAuthService return; } - // ����Ѿ�������ֱ�ӷ��� + // 如果已经撤销,直接返回 if (storedToken.IsRevoked) { _logger.LogInformation("Refresh token already revoked"); return; } - // ���� Token + // 撤销 Token storedToken.RevokedAt = DateTime.Now; storedToken.RevokedByIp = ipAddress; @@ -768,14 +779,14 @@ public class AuthService : IAuthService } /// - /// �����û������� Token + /// 撤销用户所有的 Token /// Requirements: 4.4 /// public async Task RevokeAllUserTokensAsync(long userId, string? ipAddress) { try { - // �����û�������Ч�� Token + // 查找用户所有有效的 Token var activeTokens = await _dbContext.UserRefreshTokens .Where(t => t.UserId == userId && t.RevokedAt == null) .ToListAsync(); @@ -809,7 +820,7 @@ public class AuthService : IAuthService #region Private Helper Methods /// - /// �ϲ��˻� - ����ǰ�û���openidǨ�Ƶ��ֻ����û� + /// 合并账户 - 将当前用户的openid迁移到手机号用户 /// private async Task MergeAccountsAsync(User currentUser, User mobileUser) { @@ -819,7 +830,7 @@ public class AuthService : IAuthService _logger.LogInformation("Merging accounts: CurrentUserId={CurrentUserId}, MobileUserId={MobileUserId}", currentUser.Id, mobileUser.Id); - // 5.2 ����ǰ�û���openidǨ�Ƶ��ֻ����û� + // 5.2 将当前用户的openid迁移到手机号用户 if (!string.IsNullOrWhiteSpace(currentUser.OpenId)) { mobileUser.OpenId = currentUser.OpenId; @@ -831,13 +842,13 @@ public class AuthService : IAuthService mobileUser.UpdateTime = DateTime.Now; _dbContext.Users.Update(mobileUser); - // ɾ����ǰ�û� + // 删除当前用户 _dbContext.Users.Remove(currentUser); await _dbContext.SaveChangesAsync(); await transaction.CommitAsync(); - // 5.3 �����µ�token + // 5.3 生成新的token var newToken = _jwtService.GenerateToken(mobileUser); _logger.LogInformation("Accounts merged successfully: NewUserId={NewUserId}", mobileUser.Id); @@ -906,18 +917,18 @@ public class AuthService : IAuthService } /// - /// ����Ĭ��ͷ��URL + /// 生成默认头像URL /// private static string GenerateDefaultAvatar(string seed) { - // ʹ����������һ���򵥵�Ĭ��ͷ��URL - // ʵ����Ŀ�п���ʹ��Identicon�������ͷ�����ɷ��� + // 使用随机数生成一个简单的默认头像URL + // 实际项目中可以使用Identicon或其他头像生成方案 var hash = ComputeMd5(seed); return $"https://api.dicebear.com/7.x/identicon/svg?seed={hash}"; } /// - /// ����MD5��ϣ + /// 计算MD5哈希 /// private static string ComputeMd5(string input) { @@ -927,7 +938,7 @@ public class AuthService : IAuthService } /// - /// ��������ַ��� + /// 生成随机字符串 /// private static string GenerateRandomString(int length) { @@ -941,7 +952,7 @@ public class AuthService : IAuthService } /// - /// �����ֻ��� + /// 手机号脱敏 /// private static string MaskMobile(string mobile) { @@ -952,7 +963,7 @@ public class AuthService : IAuthService } /// - /// ��ȡ����е����� + /// 获取年份中的周数 /// private static int GetWeekOfYear(DateTime date) { @@ -961,7 +972,7 @@ public class AuthService : IAuthService } /// - /// ���� SHA256 ��ϣֵ + /// 计算 SHA256 哈希值 /// Requirements: 4.1 /// private static string ComputeSha256Hash(string input) @@ -972,7 +983,7 @@ public class AuthService : IAuthService } /// - /// ���ɰ�ȫ������ַ��������� Refresh Token�� + /// 生成安全随机字符串(用于 Refresh Token) /// private static string GenerateSecureRandomString(int length) {