V1.0.5
新增用户重置密码和修改密码
This commit is contained in:
parent
57402e0dda
commit
a23984c9f5
78
LMS.Common/Password/RandomNumberGenerator.cs
Normal file
78
LMS.Common/Password/RandomNumberGenerator.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
namespace LMS.Common.Password
|
||||||
|
{
|
||||||
|
public static class PasswordGenerator
|
||||||
|
{
|
||||||
|
private const string LowercaseChars = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
private const string UppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
private const string NumberChars = "0123456789";
|
||||||
|
private const string SpecialChars = "@$!%*?.&";
|
||||||
|
private const string AllChars = LowercaseChars + UppercaseChars + NumberChars + SpecialChars;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成指定长度的随机密码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">密码长度</param>
|
||||||
|
/// <returns>随机生成的密码</returns>
|
||||||
|
public static string GeneratePassword(int length)
|
||||||
|
{
|
||||||
|
if (length < 4)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("密码长度必须至少为4个字符", nameof(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用加密安全的随机数生成器
|
||||||
|
using var rng = RandomNumberGenerator.Create();
|
||||||
|
// 确保密码包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符
|
||||||
|
var password = new StringBuilder();
|
||||||
|
|
||||||
|
// 添加每种类型的至少一个字符
|
||||||
|
password.Append(GetRandomChar(LowercaseChars, rng));
|
||||||
|
password.Append(GetRandomChar(UppercaseChars, rng));
|
||||||
|
password.Append(GetRandomChar(NumberChars, rng));
|
||||||
|
password.Append(GetRandomChar(SpecialChars, rng));
|
||||||
|
|
||||||
|
// 添加剩余的随机字符
|
||||||
|
for (int i = 4; i < length; i++)
|
||||||
|
{
|
||||||
|
password.Append(GetRandomChar(AllChars, rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打乱字符顺序
|
||||||
|
return ShuffleString(password.ToString(), rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从指定字符集中获取一个随机字符
|
||||||
|
/// </summary>
|
||||||
|
private static char GetRandomChar(string chars, RandomNumberGenerator rng)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[1];
|
||||||
|
rng.GetBytes(data);
|
||||||
|
return chars[data[0] % chars.Length];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打乱字符串中字符的顺序
|
||||||
|
/// </summary>
|
||||||
|
private static string ShuffleString(string input, RandomNumberGenerator rng)
|
||||||
|
{
|
||||||
|
char[] array = input.ToCharArray();
|
||||||
|
int n = array.Length;
|
||||||
|
|
||||||
|
while (n > 1)
|
||||||
|
{
|
||||||
|
byte[] box = new byte[1];
|
||||||
|
rng.GetBytes(box);
|
||||||
|
int k = box[0] % n;
|
||||||
|
n--;
|
||||||
|
char temp = array[n];
|
||||||
|
array[n] = array[k];
|
||||||
|
array[k] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,14 +9,37 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<h1>LMS Registration Code</h1>
|
<h1>LMS注册验证码</h1>
|
||||||
<p>Hi there,</p>
|
<p>您好,</p>
|
||||||
<p>Your code is <strong>{RegisterCode}</strong></p>
|
<p>您的验证码是 <strong>{RegisterCode}</strong></p>
|
||||||
<p>The code is valid for 10 minutes, if it is not you, please ignore it.</p>
|
<p>该验证码有效期为 10 分钟,如果不是您本人操作,请忽略此邮件。</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
public const string ResetPasswordHtmlTemplates = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>LMS重置密码验证码</h1>
|
||||||
|
<p>您好,</p>
|
||||||
|
<p>您的验证码是 <strong>{ResetPasswordCode}</strong></p>
|
||||||
|
<p>该验证码有效期为 10 分钟,如果不是您本人操作,请忽略此邮件。</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string ResetpasswordSuccessMail = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>LMS重置密码成功</h1>
|
||||||
|
<p>您好,</p>
|
||||||
|
<p>您的重置密码操作已经成功!</p>
|
||||||
|
<p>您的新密码是 <strong>{NewPassword}</strong></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 替换模板的占位符
|
/// 替换模板的占位符
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Net.Mail;
|
||||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||||
|
|
||||||
namespace LMS.service.Controllers
|
namespace LMS.service.Controllers
|
||||||
@ -142,6 +143,49 @@ namespace LMS.service.Controllers
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region 获取重置密码验证码
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<APIResponseModel<string>>> SendResetPasswordCode([FromBody] EmailVerificationService.SendVerificationCodeDto model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||||
|
|
||||||
|
return await _loginService.SendResetPasswordCode(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 用户自行重置密码
|
||||||
|
|
||||||
|
[HttpPost("{mail}/{code}")]
|
||||||
|
public async Task<ActionResult<APIResponseModel<string>>> ResetPassword(string mail, string code)
|
||||||
|
{
|
||||||
|
// 校验邮箱是不是有效
|
||||||
|
if (string.IsNullOrWhiteSpace(mail))
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "无效的邮箱");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 尝试创建MailAddress实例,如果成功则表示邮箱格式正确
|
||||||
|
MailAddress mailAddress = new(mail);
|
||||||
|
bool isMail = mailAddress.Address == mail;
|
||||||
|
if (!isMail)
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "无效的邮箱");
|
||||||
|
return await _loginService.UserResetPassword(mail, code);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
// 创建失败表示邮箱格式不正确
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "无效的邮箱");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 刷新token
|
#region 刷新token
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -256,7 +300,7 @@ namespace LMS.service.Controllers
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 管理员重置用户密码
|
#region 重置用户密码
|
||||||
|
|
||||||
[HttpPost("{id}")]
|
[HttpPost("{id}")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
|||||||
@ -23,7 +23,13 @@ public class EmailVerificationService
|
|||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成并发送验证码
|
#region 注册验证码
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送注册验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public async Task SendVerificationCodeAsync(string email)
|
public async Task SendVerificationCodeAsync(string email)
|
||||||
{
|
{
|
||||||
// 生成6位数验证码
|
// 生成6位数验证码
|
||||||
@ -46,7 +52,12 @@ public class EmailVerificationService
|
|||||||
await _emailService.SendEmailAsync(email, "LMS注册验证码", emailBody);
|
await _emailService.SendEmailAsync(email, "LMS注册验证码", emailBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证用户提交的验证码
|
/// <summary>
|
||||||
|
/// 验证用户提交的验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public async Task<bool> VerifyCodeAsync(string email, string code)
|
public async Task<bool> VerifyCodeAsync(string email, string code)
|
||||||
{
|
{
|
||||||
var storedCode = await _cache.GetStringAsync($"EmailVerification_{email}");
|
var storedCode = await _cache.GetStringAsync($"EmailVerification_{email}");
|
||||||
@ -64,8 +75,84 @@ public class EmailVerificationService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成一个6位数的验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
|
||||||
private string GenerateVerificationCode()
|
private string GenerateVerificationCode()
|
||||||
{
|
{
|
||||||
return _random.Next(100000, 999999).ToString();
|
return _random.Next(100000, 999999).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 重置密码验证码
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送重置密码验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendResetPasswordCodeAsync(string email)
|
||||||
|
{
|
||||||
|
// 生成6位数验证码
|
||||||
|
string resetPasswordCode = GenerateVerificationCode();
|
||||||
|
// 将验证码保存到分布式缓存,设置10分钟过期
|
||||||
|
var options = new DistributedCacheEntryOptions
|
||||||
|
{
|
||||||
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
|
||||||
|
};
|
||||||
|
await _cache.SetStringAsync($"ResetPassword_{email}", resetPasswordCode, options);
|
||||||
|
var emailBody = EmailTemplateService.ReplaceTemplate(EmailTemplateService.ResetPasswordHtmlTemplates, new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "ResetPasswordCode", resetPasswordCode }
|
||||||
|
});
|
||||||
|
// 发送验证码邮件
|
||||||
|
await _emailService.SendEmailAsync(email, "LMS重置密码验证码", emailBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 严重用户提交成的重置密码验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> VerifyResetPasswordAsync(string email, string code)
|
||||||
|
{
|
||||||
|
var storedCode = await _cache.GetStringAsync($"ResetPassword_{email}");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(storedCode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 使用完就删除验证码
|
||||||
|
if (storedCode == code)
|
||||||
|
{
|
||||||
|
await _cache.RemoveAsync($"ResetPassword_{email}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region 重置密码成功邮件
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送重置密码验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendResetpasswordSuccessMail(string email, string newPassword)
|
||||||
|
{
|
||||||
|
var emailBody = EmailTemplateService.ReplaceTemplate(EmailTemplateService.ResetpasswordSuccessMail, new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "NewPassword", newPassword }
|
||||||
|
});
|
||||||
|
// 发送验证码邮件
|
||||||
|
await _emailService.SendEmailAsync(email, "LMS重置密码成功", emailBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -391,8 +391,11 @@ namespace LMS.service.Service
|
|||||||
query = query.Where(x => filteredOwnerIds.Contains(x.UserID));
|
query = query.Where(x => filteredOwnerIds.Contains(x.UserID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSuperAdmin)
|
||||||
|
{
|
||||||
|
|
||||||
if (isAdmin && !isSuperAdmin)
|
}
|
||||||
|
else if (isAdmin)
|
||||||
{
|
{
|
||||||
// 除了超级管理员的代理 其他都能看到
|
// 除了超级管理员的代理 其他都能看到
|
||||||
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
||||||
@ -408,7 +411,7 @@ namespace LMS.service.Service
|
|||||||
query = query.Where(x => !filteredParentIds.Contains(x.UserID) || x.UserID == requestUserId);
|
query = query.Where(x => !filteredParentIds.Contains(x.UserID) || x.UserID == requestUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isAgent && !isSuperAdmin)
|
else if (isAgent)
|
||||||
{
|
{
|
||||||
// 代理只能看到自己下面的用户
|
// 代理只能看到自己下面的用户
|
||||||
var list = await userLookupQuery
|
var list = await userLookupQuery
|
||||||
@ -417,10 +420,18 @@ namespace LMS.service.Service
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
HashSet<long> filteredParentIds = new(list);
|
HashSet<long> filteredParentIds = new(list);
|
||||||
if (filteredParentIds?.Count > 0)
|
if (filteredParentIds != null)
|
||||||
{
|
{
|
||||||
query = query.Where(x => filteredParentIds.Contains(x.UserID) || x.UserID == requestUserId);
|
query = query.Where(x => filteredParentIds.Contains(x.UserID) || x.UserID == requestUserId);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.UserID == user.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.UserID == user.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -291,7 +291,11 @@ namespace LMS.service.Service.SoftwareService
|
|||||||
// 做筛选权限
|
// 做筛选权限
|
||||||
// 获取相关用户ID
|
// 获取相关用户ID
|
||||||
var userLookupQuery = _userManager.Users.AsNoTracking();
|
var userLookupQuery = _userManager.Users.AsNoTracking();
|
||||||
if (isAdmin && !isSuperAdmin)
|
if (isSuperAdmin)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (isAdmin)
|
||||||
{
|
{
|
||||||
// 除了超级管理员的代理 其他都能看到
|
// 除了超级管理员的代理 其他都能看到
|
||||||
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
||||||
@ -307,7 +311,7 @@ namespace LMS.service.Service.SoftwareService
|
|||||||
query = query.Where(x => !filteredParentIds.Contains(x.UserId) || x.UserId == requestUserId);
|
query = query.Where(x => !filteredParentIds.Contains(x.UserId) || x.UserId == requestUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isAgent && !isSuperAdmin)
|
else if (isAgent)
|
||||||
{
|
{
|
||||||
// 代理只能看到自己下面的用户
|
// 代理只能看到自己下面的用户
|
||||||
var list = await userLookupQuery
|
var list = await userLookupQuery
|
||||||
@ -316,12 +320,16 @@ namespace LMS.service.Service.SoftwareService
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
HashSet<long> filteredParentIds = new(list);
|
HashSet<long> filteredParentIds = new(list);
|
||||||
if (filteredParentIds?.Count > 0)
|
if (filteredParentIds != null)
|
||||||
{
|
{
|
||||||
query = query.Where(x => filteredParentIds.Contains(x.UserId));
|
query = query.Where(x => filteredParentIds.Contains(x.UserId));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.UserId == requestUserId);
|
||||||
}
|
}
|
||||||
else if (!isSuperAdmin)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// 普通用户只能看到自己的
|
// 普通用户只能看到自己的
|
||||||
query = query.Where(x => x.UserId == requestUserId);
|
query = query.Where(x => x.UserId == requestUserId);
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
using LMS.Common.Enum;
|
||||||
|
using LMS.Common.Password;
|
||||||
using LMS.Common.RSAKey;
|
using LMS.Common.RSAKey;
|
||||||
using LMS.DAO;
|
using LMS.DAO;
|
||||||
using LMS.DAO.UserDAO;
|
using LMS.DAO.UserDAO;
|
||||||
@ -15,16 +17,18 @@ using System.Collections.Concurrent;
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using static Betalgo.Ranul.OpenAI.ObjectModels.SharedModels.IOpenAIModels;
|
||||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||||
|
|
||||||
namespace LMS.service.Service.UserService
|
namespace LMS.service.Service.UserService
|
||||||
{
|
{
|
||||||
public class LoginService(UserManager<User> userManager, ApplicationDbContext context, SecurityService securityService, UserBasicDao userBasicDao)
|
public class LoginService(UserManager<User> userManager, ApplicationDbContext context, SecurityService securityService, UserBasicDao userBasicDao, EmailVerificationService emailVerificationService)
|
||||||
{
|
{
|
||||||
private readonly UserManager<User> _userManager = userManager;
|
private readonly UserManager<User> _userManager = userManager;
|
||||||
private readonly ApplicationDbContext _context = context;
|
private readonly ApplicationDbContext _context = context;
|
||||||
private readonly SecurityService _securityService = securityService;
|
private readonly SecurityService _securityService = securityService;
|
||||||
private readonly UserBasicDao _userBasicDao = userBasicDao;
|
private readonly UserBasicDao _userBasicDao = userBasicDao;
|
||||||
|
private readonly EmailVerificationService _verificationService = emailVerificationService;
|
||||||
|
|
||||||
#region 生成JWT
|
#region 生成JWT
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -417,7 +421,8 @@ namespace LMS.service.Service.UserService
|
|||||||
}
|
}
|
||||||
// 检查当前用户是不是超级管理员
|
// 检查当前用户是不是超级管理员
|
||||||
bool isSuperAdmin = await _userBasicDao.CheckUserIsSuperAdmin(requestUserId);
|
bool isSuperAdmin = await _userBasicDao.CheckUserIsSuperAdmin(requestUserId);
|
||||||
if (!isSuperAdmin)
|
// 不是超级管理员,不能重置其他用户的密码
|
||||||
|
if (!isSuperAdmin && id != requestUserId)
|
||||||
{
|
{
|
||||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||||
}
|
}
|
||||||
@ -458,5 +463,97 @@ namespace LMS.service.Service.UserService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 发送重置密码验证码
|
||||||
|
internal async Task<ActionResult<APIResponseModel<string>>> SendResetPasswordCode(EmailVerificationService.SendVerificationCodeDto model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检查邮箱是否已被使用
|
||||||
|
var existingUser = await _userManager.FindByEmailAsync(model.Email);
|
||||||
|
if (existingUser == null)
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "当前邮箱未注册,请先注册!");
|
||||||
|
|
||||||
|
Options? enaleMailService = await _context.Options.FirstOrDefaultAsync(x => x.Key == OptionKeyName.EnableMailService);
|
||||||
|
if (enaleMailService != null)
|
||||||
|
{
|
||||||
|
_ = bool.TryParse(enaleMailService.Value, out bool enableMail);
|
||||||
|
if (!enableMail)
|
||||||
|
{
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, "邮件服务未开启,无法重置密码!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
await _verificationService.SendResetPasswordCodeAsync(model.Email);
|
||||||
|
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success, "验证码发送成功,请在邮箱中查收!");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region 用户自行重置密码
|
||||||
|
public async Task<ActionResult<APIResponseModel<string>>> UserResetPassword(string mail, string code)
|
||||||
|
{
|
||||||
|
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检查邮箱是否已被使用
|
||||||
|
var existingUser = await _userManager.FindByEmailAsync(mail);
|
||||||
|
if (existingUser == null)
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "当前邮箱未注册,请先注册!");
|
||||||
|
// 校验验证码
|
||||||
|
Options? enaleMailService = await _context.Options.FirstOrDefaultAsync(x => x.Key == OptionKeyName.EnableMailService);
|
||||||
|
if (enaleMailService != null)
|
||||||
|
{
|
||||||
|
_ = bool.TryParse(enaleMailService.Value, out bool enableMail);
|
||||||
|
if (!enableMail)
|
||||||
|
{
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, "邮件服务未开启,无法重置密码!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isCodeValid = await _verificationService.VerifyResetPasswordAsync(mail, code);
|
||||||
|
if (!isCodeValid)
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "验证码无效或已过期");
|
||||||
|
|
||||||
|
// 生成一个密码
|
||||||
|
string randomPassword = PasswordGenerator.GeneratePassword(12);
|
||||||
|
|
||||||
|
// 移除用户当前密码(如果用户没有密码,则需要跳过此步骤)
|
||||||
|
var hasPassword = await _userManager.HasPasswordAsync(existingUser);
|
||||||
|
if (hasPassword)
|
||||||
|
{
|
||||||
|
var removePasswordResult = await _userManager.RemovePasswordAsync(existingUser);
|
||||||
|
if (!removePasswordResult.Succeeded)
|
||||||
|
{
|
||||||
|
var errors = string.Join("; ", removePasswordResult.Errors.Select(e => e.Description));
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, $"移除旧密码失败:{errors}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为用户设置新密码
|
||||||
|
var addPasswordResult = await _userManager.AddPasswordAsync(existingUser, randomPassword);
|
||||||
|
if (!addPasswordResult.Succeeded)
|
||||||
|
{
|
||||||
|
var errors = string.Join("; ", addPasswordResult.Errors.Select(e => e.Description));
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, $"重置密码失败:{errors}");
|
||||||
|
}
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
// 重置密码成功,把新密码发送到邮箱
|
||||||
|
await _verificationService.SendResetpasswordSuccessMail(mail, randomPassword);
|
||||||
|
|
||||||
|
// 重置密码
|
||||||
|
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success, "密码重置成功,请去邮箱查看重置密码!");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,7 +139,11 @@ namespace LMS.service.Service.UserService
|
|||||||
|
|
||||||
// 获取相关用户ID
|
// 获取相关用户ID
|
||||||
var userLookupQuery = _userManager.Users.AsNoTracking();
|
var userLookupQuery = _userManager.Users.AsNoTracking();
|
||||||
if (isAdmin && !isSuperAdmin)
|
if (isSuperAdmin)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (isAdmin)
|
||||||
{
|
{
|
||||||
// 除了超级管理员的代理 其他都能看到
|
// 除了超级管理员的代理 其他都能看到
|
||||||
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
||||||
@ -155,7 +159,7 @@ namespace LMS.service.Service.UserService
|
|||||||
query = query.Where(x => !filteredParentIds.Contains(x.Id));
|
query = query.Where(x => !filteredParentIds.Contains(x.Id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isAgent && !isSuperAdmin)
|
else if (isAgent)
|
||||||
{
|
{
|
||||||
// 代理只能看到自己下面的用户
|
// 代理只能看到自己下面的用户
|
||||||
var list = await userLookupQuery
|
var list = await userLookupQuery
|
||||||
@ -164,10 +168,18 @@ namespace LMS.service.Service.UserService
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
HashSet<long> filteredParentIds = new(list);
|
HashSet<long> filteredParentIds = new(list);
|
||||||
if (filteredParentIds?.Count > 0)
|
if (filteredParentIds != null)
|
||||||
{
|
{
|
||||||
query = query.Where(x => filteredParentIds.Contains(x.Id));
|
query = query.Where(x => filteredParentIds.Contains(x.Id));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.Id == reuqertUserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.Id == reuqertUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,6 @@
|
|||||||
],
|
],
|
||||||
"Enrich": [ "FromLogContext" ]
|
"Enrich": [ "FromLogContext" ]
|
||||||
},
|
},
|
||||||
"Version": "1.0.4",
|
"Version": "1.0.5",
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user