程序地带

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理


在一些系统中,有时候用户忘记密码,可以通过向自己手机发送动态验证码的方式实现系统登录功能。本篇随笔介绍如何结合后端ABP框架的短信发送和缓存模块的处理,实现手机短信动态码登陆处理。


一般的登录方式,分为普通账号登录,动态密码登陆,扫描二维码登录等几种方式,其他方式这里不讲,主要介绍动态码登录方式。



1、短信验证码的发送处理 

 我在上篇随笔《ABP框架中短信发送处理,包括阿里云短信和普通短信商的短信发送集成》中介绍了如何使用ABP框架实现短信的发送处理,因此我们前后端通过短信的方式,可以实现动态密码的登陆处理。


因此在授权登陆的控制器中,我们增加短信发送的接口注入使用,如下所示。



 


然后通过定义两个接口,一个是发送动态验证码给用户手机的接口,一个是根据用户手机和动态验证码的方式进行登录处理接口。


然后我们在这个验证身份的控制器上增加两个方法即可。



用例也就是分了两个处理方法。



 


 在处理发送短信验证码之前,我们来介绍一下短信验证码的处理规则,我们发送短信成功后,把验证码存在系统缓存里面,一般系统缓存是存放在Redis里面,缓存需要一个键和定义好的类对象进行存储。


我们定义好存储的对象类,再在系统中使用即可。


/// <summary>
/// 短信登陆动态密码缓存对象
/// </summary>
[Serializable]
public class SmsLoginCodeCacheItem
{
public const string CacheName = "AppSmsLoginCodeCacheItem";
public string Code { get; set; }
public string PhoneNumber { get; set; }
public SmsLoginCodeCacheItem()
{
}
public SmsLoginCodeCacheItem(string code, string phone)
{
Code = code;
PhoneNumber = phone;
}
}

我们可以在系统模块初始化的时候,配置好缓存对应的失效时间,如下所示。


//配置SMS登录动态码有效期限
Configuration.Caching.Configure(SmsLoginCodeCacheItem.CacheName, cache =>
{
cache.DefaultSlidingExpireTime = TimeSpan.FromMinutes(Constants.SmsCodeExpiredMinutes);
});

发送短信验证码作为动态密码的逻辑代码如下所示。


/// <summary>
/// 发送登录动态码
/// </summary>
/// <param name="model">手机登录动态码</param>
/// <returns></returns>
[HttpPost]
public async Task<CommonResult> SendPhoneLoginSmsCode([FromBody] AuthenticateByPhoneCaptchaModel model)
{
//获取随机6位数字动态验证码
var code = RandomHelper.GetRandom(100000, 999999).ToString();
//使用自定义模板处理短信发送
string message = string.Format(Constants.MySmsCodeTemplate, code);
var result = await _smsSender.SendAsync(model.PhoneNumber, message);
if(result.Success)
{
var cacheKey = model.PhoneNumber;//以手机号码作为键存储验证码缓存
var cacheItem = new SmsLoginCodeCacheItem { Code = code, PhoneNumber = model.PhoneNumber };
var cache = _cacheManager.GetCache<string, SmsLoginCodeCacheItem>(SmsLoginCodeCacheItem.CacheName);
cache.Set(cacheKey, cacheItem);
}
return result;
}

我们还需要在前端中设计一个使用动态短信码登录的界面,如下所示。



短信发送成功,可以在用户手机查看对应的动态码。



 验证码发送后,我们也可以在Redis中看到对应的数据,如下所示。



 


2、动态码登录处理

发送了短信码后,系统在缓存中存放一段时间的数据,如果在这个期间进行登录,会根据缓存进行匹配,如果匹配成功,那么就进行相关登录身份的处理即可。


系统登录验证的处理代码如下所示。


/// <summary>
/// 通过手机验证码授权
/// </summary>
/// <param name="model">手机验证码Dto</param>
/// <returns></returns>
[HttpPost]
public async Task<AuthenticateResultModel> AuthenticateByPhoneCaptcha([FromBody] AuthenticateByPhoneCaptchaModel model)
{
var loginResult = await GetLoginResultByPhoneCaptchaAsync(
model.PhoneNumber,
model.SmsCode,
GetTenancyNameOrNull()
);
//if(loginResult.Result == AbpLoginResultType.Success)
//这里成功,移除短信缓存
var cache = _cacheManager.GetCache<string, SmsLoginCodeCacheItem>(SmsLoginCodeCacheItem.CacheName);
cache.Remove(model.PhoneNumber);//移除缓存短信键值
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
UserId = loginResult.User.Id
};
}

这里主要的逻辑封装在 GetLoginResultByPhoneCaptchaAsync 中,这个登录的方式可以参考ABP框架基础的登陆方式进行改动即可。


/// <summary>
/// 获取登陆结果通过手机验证码
/// </summary>
/// <param name="phoneNumber">手机号</param>
/// <param name="captcha">验证码</param>
/// <param name="tenancyName">租户名</param>
/// <returns></returns>
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultByPhoneCaptchaAsync(string phoneNumber, string captcha, string tenancyName)
{
var loginResult = await _logInManager.LoginByMobileAsync(phoneNumber, captcha, tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, loginResult.User.UserName, tenancyName);
}
}

参照ABP框架基础的登陆授权方式,我们在UserManager中增加类似的验证码登陆管理方式,如下所示。




前端在处理相关发送验证码和登录授权的操作,是针对API的调用,因此需要封装对应的API处理。



 


 然后仿照常规登录的处理,编写一个动态码登录的处理方式,放在对应的Module中即可。


dynamiclogin({ commit }, userInfo) { // 动态密码登陆
const { mobile, smscode } = userInfo
return new Promise((resolve, reject) => {
tokenauth.AuthenticateByPhoneCaptcha({ phoneNumber: mobile.trim(), smsCode: smscode }).then(response => {
const { result } = response // 获取返回对象的 result
// console.log(result)// 记录数据
var token = result.accessToken // 用户令牌
var userId = result.userId // 用户id
// 修改State对象,记录令牌和用户Id
commit("SET_TOKEN", token)
commit("SET_USERID", userId)
// 存储cookie
setToken(token)
setUserId(userId)
resolve()
}).catch(error => {
reject(error)
})
})
},

 


 在登录界面中,输入动态码登录即可顺利进入系统,和常规的处理一样。



 


 以上就是参照常规账号密码登录的方式,构建一个动态码登录的处理,流程还是差不多,不过整合了短信发送,缓存处理,账号登陆等几个流程,可以作为一个简单的系统登录过程的了解。


 


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wuhuacong/p/14240372.html

随机推荐

webpack打包原理_带你看懂 HMR 热更新原理

现在的我们基本上都是使用webpack模式开发,修改了代码之后,页面会直接进行改变,但是很少有人想过,为什么页面不刷新就会直接改变了࿱...

weixin_39663602 阅读(428)

webpack打包流程_深入浅出webpack

Webpack 是一个打包模块化JavaScript的工具,在Webpack里一切文件皆模块,通过Loader转换文件,通过Plugin注入钩子,...

weixin_40000131 阅读(380)

nacos动态切换数据源

在上一篇博客中介绍到可以使用nacos作为分布式配置中心,在这边博客中将介绍nacos实现数据源的热更新1.准备工作:在两个不同的数据库中执行同样的建表语句,...

踏雪江南 阅读(937)

CTF学习笔记——[极客大挑战 2019]Http

一、[极客大挑战2019]Http1.题目2.解题步骤查看源码的时候发现这里有链接然后访问发现猜测需要用burp抓包更改请求头再访问更改之后提示syclover浏览器访问,于是继续更改啊...

Obs_cure 阅读(150)

webpack打包流程_Webpack 构建流程学习指南

Webpack是前端很火的打包工具,它本质上是一个现代JavaScript应用程序的静态模块打包器(modulebundler)。当Webpack处理应用程序时,它会递归地...

weixin_39725594 阅读(115)