Skip to content

Commit

Permalink
Update AccountContracts and AccountController to use formatted keys f…
Browse files Browse the repository at this point in the history
…or Redis operations
  • Loading branch information
luoyunchong committed May 19, 2024
1 parent 26e6ab5 commit 1fc9764
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 49 deletions.
19 changes: 19 additions & 0 deletions src/LinCms.Application/Cms/Account/AccountContracts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace LinCms.Cms.Account;

public class AccountContracts
{
/// <summary>
/// 注册返回的uuid值
/// </summary>
public static string SendEmailCode_EmailCode = "AccountService.SendEmailCode.EmailCode.{0}";
/// <summary>
/// 注册时缓存的邮件验证码
/// </summary>
public static string SendEmailCode_VerificationCode = "AccountService.SendEmailCode.VerificationCode.{0}";

/// <summary>
/// 重置密码时邮件验证码
/// </summary>
public static string SendPasswordResetCode_VerificationCode = "AccountService.SendPasswordResetCode.VerificationCode.{0}";

}
79 changes: 33 additions & 46 deletions src/LinCms.Application/Cms/Account/AccountService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,19 @@

namespace LinCms.Cms.Account;

public class AccountService : ApplicationService, IAccountService
{
private readonly IAuditBaseRepository<LinUser, long> _userRepository;
private readonly IEmailSender _emailSender;
private readonly MailKitOptions _mailKitOptions;
private readonly IUserIdentityService _userIdentityService;
private readonly SiteOption _siteOption;
private readonly ICaptchaManager _captchaManager;
private readonly CaptchaOption _loginCaptchaOption;
private readonly IRedisClient _redisClient;
public AccountService(
IAuditBaseRepository<LinUser, long> userRepository,
public class AccountService(IAuditBaseRepository<LinUser, long> userRepository,
IEmailSender emailSender,
IOptions<MailKitOptions> options,
IUserIdentityService userIdentityService,
IOptionsMonitor<SiteOption> siteOption,
ICaptchaManager captchaManager,
IOptionsMonitor<CaptchaOption> loginCaptchaOption,
IRedisClient redisClient)
{
_userRepository = userRepository;
_emailSender = emailSender;
_mailKitOptions = options.Value;
_userIdentityService = userIdentityService;
_siteOption = siteOption.CurrentValue;
_captchaManager = captchaManager;
_loginCaptchaOption = loginCaptchaOption.CurrentValue;
_redisClient = redisClient;
}
: ApplicationService, IAccountService
{
private readonly MailKitOptions _mailKitOptions = options.Value;
private readonly SiteOption _siteOption = siteOption.CurrentValue;
private readonly CaptchaOption _loginCaptchaOption = loginCaptchaOption.CurrentValue;

/// <summary>
/// 生成无状态的登录验证码
Expand All @@ -52,9 +36,9 @@ public AccountService(
public LoginCaptchaDto GenerateCaptcha()
{
//if (_loginCaptchaOption.Enabled == false) return new LoginCaptchaDto();
string captcha = _captchaManager.GetRandomString(CaptchaManager.RandomStrNum);
string base64String = _captchaManager.GetRandomCaptchaBase64(captcha);
string tag = _captchaManager.GetTag(captcha, _loginCaptchaOption.Salt);
string captcha = captchaManager.GetRandomString(CaptchaManager.RandomStrNum);
string base64String = captchaManager.GetRandomCaptchaBase64(captcha);
string tag = captchaManager.GetTag(captcha, _loginCaptchaOption.Salt);
return new LoginCaptchaDto(tag, "data:image/png;base64," + base64String);
}

Expand All @@ -66,8 +50,8 @@ public LoginCaptchaDto GenerateCaptcha()
/// <returns></returns>
public bool VerifyCaptcha(String captcha, String tag)
{
var captchaBo = _captchaManager.DecodeTag(tag, _loginCaptchaOption.Salt);
long t = _captchaManager.GetTimeStamp();
var captchaBo = captchaManager.DecodeTag(tag, _loginCaptchaOption.Salt);
long t = captchaManager.GetTimeStamp();
return string.Compare(captchaBo.Captcha, captcha, StringComparison.OrdinalIgnoreCase) == 0 && t > captchaBo.Expired;
}

Expand All @@ -81,7 +65,7 @@ public bool VerifyCaptcha(String captcha, String tag)
/// <exception cref="LinCmsException"></exception>
public async Task<string> SendChangeEmailAsync(SendEmailCodeInput sendEmailCodeInput)
{
var isRepeatEmail = await _userRepository.Select.AnyAsync(r => r.Email == sendEmailCodeInput.Email.Trim());
var isRepeatEmail = await userRepository.Select.AnyAsync(r => r.Email == sendEmailCodeInput.Email.Trim());
if (isRepeatEmail)
{
throw new LinCmsException("该邮箱重复,请重新输入", ErrorCode.RepeatField);
Expand All @@ -93,7 +77,7 @@ public async Task<string> SendChangeEmailAsync(SendEmailCodeInput sendEmailCodeI
message.Subject = $"vvlog-请点击这里激活您的账号";

string uuid = Guid.NewGuid().ToString();
await _redisClient.SetAsync("SendChangeEmail." + sendEmailCodeInput.Email, uuid, 30 * 60);
await redisClient.SetAsync("SendChangeEmail." + sendEmailCodeInput.Email, uuid, 30 * 60);

message.Body = new TextPart("html")
{
Expand All @@ -103,15 +87,15 @@ 感谢您在 vvlog的注册,请点击这里激活您的账号:</br>
祝您使用愉快,使用过程中您有任何问题请及时联系我们。</br>"
};

await _emailSender.SendAsync(message);
await emailSender.SendAsync(message);
return "";
}
#endregion


public async Task<string> SendEmailCodeAsync(RegisterEmailCodeInput registerDto)
{
var isRepeatEmail = await _userRepository.Select.AnyAsync(r => r.Email == registerDto.Email.Trim());
var isRepeatEmail = await userRepository.Select.AnyAsync(r => r.Email == registerDto.Email.Trim());
if (isRepeatEmail)
{
throw new LinCmsException("该邮箱已注册,请更换", ErrorCode.RepeatField);
Expand All @@ -122,18 +106,20 @@ public async Task<string> SendEmailCodeAsync(RegisterEmailCodeInput registerDto)
message.To.Add(new MailboxAddress(registerDto.Email, registerDto.Email));
message.Subject = $"vvlog-你的验证码是";

string uuid = Guid.NewGuid().ToString();
await _redisClient.SetAsync("SendEmailCode." + registerDto.Email, uuid, 30 * 60);
string uuid = Guid.NewGuid().ToString();
string key = string.Format(AccountContracts.SendEmailCode_EmailCode, registerDto.Email);
await redisClient.SetAsync(key, uuid, 30 * 60);

int verificationCode = new Random().Next(100000, 999999);

message.Body = new TextPart("html")
{
Text = $@"{registerDto.Email},您好!</br>你此次验证码如下,请在 30 分钟内输入验证码进行下一步操作。</br>如非你本人操作,请忽略此邮件。</br>{verificationCode}"
};

await _emailSender.SendAsync(message);
await _redisClient.SetAsync("SendEmailCode.VerificationCode." + registerDto.Email, verificationCode, 30 * 60);

string keyVerificationCode = string.Format(AccountContracts.SendEmailCode_VerificationCode, registerDto.Email);
await emailSender.SendAsync(message);
await redisClient.SetAsync(keyVerificationCode, verificationCode, 30 * 60);
return uuid;
}

Expand All @@ -160,18 +146,18 @@ public async Task<string> SendPasswordResetCodeAsync(SendEmailCodeInput sendEmai
Text = $@"{user.Nickname},您好!</br>你此次重置密码的验证码如下,请在 30 分钟内输入验证码进行下一步操作。</br>如非你本人操作,请忽略此邮件。</br>{verificationCode}"
};

await _userRepository.UpdateAsync(user);

await _emailSender.SendAsync(message);
await userRepository.UpdateAsync(user);

await _redisClient.SetAsync(user.Email, verificationCode, 30 * 60);
await emailSender.SendAsync(message);
string key = string.Format(AccountContracts.SendPasswordResetCode_VerificationCode, user.Email);
await redisClient.SetAsync(key, verificationCode, 30 * 60);

return user.PasswordResetCode;
}

private async Task<LinUser> GetUserByChecking(string inputEmailAddress)
{
var user = await _userRepository.Select.Where(r => r.Email == inputEmailAddress).FirstAsync();
var user = await userRepository.Select.Where(r => r.Email == inputEmailAddress).FirstAsync();
if (user == null)
{
throw new LinCmsException("InvalidEmailAddress");
Expand All @@ -182,8 +168,9 @@ private async Task<LinUser> GetUserByChecking(string inputEmailAddress)

public async Task ResetPasswordAsync(ResetEmailPasswordDto resetPassword)
{
string resetCode = await _redisClient.GetAsync(resetPassword.Email);
if (resetCode.IsNullOrEmpty())
string key = string.Format(AccountContracts.SendPasswordResetCode_VerificationCode, resetPassword.Email);
string resetCode = await redisClient.GetAsync(key);
if (resetCode.IsNullOrWhiteSpace())
{
throw new LinCmsException("验证码已过期");
}
Expand All @@ -192,14 +179,14 @@ public async Task ResetPasswordAsync(ResetEmailPasswordDto resetPassword)
throw new LinCmsException("验证码不正确");//InvalidEmailConfirmationCode
}

var user = await _userRepository.Select.Where(r => r.Email == resetPassword.Email).FirstAsync();
var user = await userRepository.Select.Where(r => r.Email == resetPassword.Email).FirstAsync();
if (user == null || resetPassword.PasswordResetCode != user.PasswordResetCode)
{
throw new LinCmsException("该请求无效,请重新获取验证码");
}

user.PasswordResetCode = null;
await _userRepository.UpdateAsync(user);
await _userIdentityService.ChangePasswordAsync(user.Id, resetPassword.Password, user.Salt);
await userRepository.UpdateAsync(user);
await userIdentityService.ChangePasswordAsync(user.Id, resetPassword.Password, user.Salt);
}
}
12 changes: 9 additions & 3 deletions src/LinCms.Web/Controllers/Cms/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,26 @@ public async Task<string> SendEmailCodeAsync([FromBody] RegisterEmailCodeInput r
[HttpPost("account/register")]
public async Task<UnifyResponseDto> Register([FromBody] RegisterDto registerDto, [FromServices] IMapper mapper, [FromServices] IUserService userSevice)
{
string uuid = await _redisClient.GetAsync("SendEmailCode." + registerDto.Email);
string key = string.Format(AccountContracts.SendEmailCode_EmailCode, registerDto.Email);
string uuid = await _redisClient.GetAsync(key);

if (uuid != registerDto.EmailCode)
{
return UnifyResponseDto.Error("非法请求");
}

string verificationCode = await _redisClient.GetAsync("SendEmailCode.VerificationCode" + registerDto.Email);
string keyVerificationCode = string.Format(AccountContracts.SendEmailCode_VerificationCode, registerDto.Email);
string verificationCode = await _redisClient.GetAsync(keyVerificationCode);
if (string.IsNullOrWhiteSpace(verificationCode))
{
return UnifyResponseDto.Error("验证码已过期");
}
if (verificationCode != registerDto.VerificationCode)
{
return UnifyResponseDto.Error("验证码不正确");
}
//验证通过后,删除redis中的验证码
await _redisClient.DelAsync("SendEmailCode." + registerDto.Email);
await _redisClient.DelAsync(keyVerificationCode);
LinUser user = mapper.Map<LinUser>(registerDto);
user.IsEmailConfirmed = true;
await userSevice.CreateAsync(user, new List<long>(), registerDto.Password);
Expand Down

0 comments on commit 1fc9764

Please sign in to comment.