一 Abp.Zero 手机号免密登录验证与号码绑定功能的实现:验证码模块( 二 )

public class SmsCaptchaManager : DomainService, ICaptchaManager{private readonly ISmsService SmsService;private readonly UserManager _userManager;private readonly SmsCaptchaTokenCache captchaTokenCache;public static TimeSpan TokenCacheDuration = TimeSpan.FromMinutes(5);public SmsCaptchaManager(ISmsService SmsService,UserManager userManager,SmsCaptchaTokenCache captchaTokenCache){this.SmsService=SmsService;_userManager=userManager;this.captchaTokenCache=captchaTokenCache;}}新建SendCaptchaAsync方法,作为短信发送和缓存Token方法,CommonHelp中的GetRandomCaptchaNumber()用于生成随机6位验证码 , 发送完毕后,将此验证码作为缓存条目的Key值存入
public async Task SendCaptchaAsync(long userId, string phoneNumber, string purpose){var captcha = CommonHelper.GetRandomCaptchaNumber();var model = new SendSmsRequest();model.PhoneNumbers= phoneNumber;model.SignName="MatoApp";model.TemplateCode= purpose switch{CaptchaPurpose.BIND_PHONENUMBER => "SMS_255330989",CaptchaPurpose.UNBIND_PHONENUMBER => "SMS_255330923",CaptchaPurpose.LOGIN => "SMS_255330901",CaptchaPurpose.IDENTITY_VERIFICATION => "SMS_255330974"};model.TemplateParam= JsonConvert.SerializeObject(new { code = captcha });var result = await SmsService.SendSmsAsync(model);if (string.IsNullOrEmpty(result.BizId) && result.Code!="OK"){throw new UserFriendlyException("验证码发送失败,错误信息:"+result.Message);}await captchaTokenCache.SetAsync(captcha, new SmsCaptchaTokenCacheItem(){PhoneNumber=phoneNumber,UserId=userId,Purpose=purpose}, absoluteExpireTime: DateTimeOffset.Now.Add(TokenCacheDuration));}绑定手机号功能实现
public async Task BindAsync(string token){SmsCaptchaTokenCacheItem currentItem = await GetToken(token);if (currentItem==null || currentItem.Purpose!=CaptchaPurpose.BIND_PHONENUMBER){throw new UserFriendlyException("验证码不正确或已过期");}var user = await _userManager.GetUserByIdAsync(currentItem.UserId);if (user.IsPhoneNumberConfirmed){throw new UserFriendlyException("已绑定手机,请先解绑后再绑定");}user.PhoneNumber=currentItem.PhoneNumber;user.IsPhoneNumberConfirmed=true;await _userManager.UpdateAsync(user);await RemoveToken(token);}解绑手机号功能实现
public async Task UnbindAsync(string token){SmsCaptchaTokenCacheItem currentItem = await GetToken(token);if (currentItem==null|| currentItem.Purpose!=CaptchaPurpose.UNBIND_PHONENUMBER){throw new UserFriendlyException("验证码不正确或已过期");}var user = await _userManager.GetUserByIdAsync(currentItem.UserId);user.IsPhoneNumberConfirmed=false;await _userManager.UpdateAsync(user);await RemoveToken(token);}验证功能实现
public async Task<bool> VerifyCaptchaAsync(string token, string purpose = CaptchaPurpose.IDENTITY_VERIFICATION){SmsCaptchaTokenCacheItem currentItem = await GetToken(token);if (currentItem==null || currentItem.Purpose!=purpose){return false;}await RemoveToken(token);return true;}实际业务中可能还需要Email验证,我也建立了电子邮箱验证码的领域服务类,只不过没有实现它 , 动手能力强的读者可以试着完善这个小案例:)

一 Abp.Zero 手机号免密登录验证与号码绑定功能的实现:验证码模块

文章插图
Api实现AppService层创建CaptchaAppService.cs,并写好接口
public class CaptchaAppService : ApplicationService{private readonly SmsCaptchaManager captchaManager;public CaptchaAppService(SmsCaptchaManager captchaManager){this.captchaManager=captchaManager;}[HttpPost]public async Task SendAsync(SendCaptchaInput input){await captchaManager.SendCaptchaAsync(input.UserId, input.PhoneNumber, input.Type);}[HttpPost]public async Task VerifyAsync(VerifyCaptchaInput input){await captchaManager.VerifyCaptchaAsync(input.Token);}[HttpPost]public async Task UnbindAsync(VerifyCaptchaInput input){await captchaManager.UnbindAsync(input.Token);}[HttpPost]public async Task BindAsync(VerifyCaptchaInput input){await captchaManager.BindAsync(input.Token);}}
一 Abp.Zero 手机号免密登录验证与号码绑定功能的实现:验证码模块

文章插图
至此我们就完成了验证码相关逻辑的接口下一章将介绍如何重写Abp默认方法,以集成手机号登录功能 。
注意!不要将本示例作为生产级代码使用本示例中,验证码校验的接口并没有做严格加密 , 6位验证码也很容易被破解,因此需要考虑这些安全问题 。在实际生产代码中 , 验证的参数常用手机号+验证码做哈希运算保证安全 。
项目地址Github:matoapp-samples
【一 Abp.Zero 手机号免密登录验证与号码绑定功能的实现:验证码模块】

推荐阅读