在一些系统中,有时候用户忘记密码,可以通过向自己手机发送动态验证码的方式实现系统登录功能。本篇随笔介绍如何结合后端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)
})
})
},

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

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

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

  1. 循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

    在我们使用Vue+Element开发前端的时候,往往涉及到很多界面组件的使用,其中很多直接采用Element官方的案例即可,有些则是在这个基础上封装更好利用.更少代码的组件:另外有些则是直接采用第三方 ...

  2. 循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

    在前面随笔<循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理>中介绍了在Vue + Element整合框架中,实现了动态菜单和动态路由的处理,从而可以根据 ...

  3. 循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理

    在我们一般开发的系统界面里面,列表页面是一个非常重要的综合展示界面,包括有条件查询.列表展示和分页处理,以及对每项列表内容可能进行的转义处理,本篇随笔介绍基于Vue +Element基础上实现表格列表 ...

  4. 循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

    在我们开发BS页面的时候,往往需要了解常规界面组件的使用,小到最普通的单文本输入框.多文本框.下拉列表,以及按钮.图片展示.弹出对话框.表单处理.条码二维码等等,本篇随笔基于普通表格业务的展示录入的场 ...

  5. 循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用

    在我前面随笔<循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用>里面曾经介绍过一些常规的界面组件的处理,主要介绍到单文本输入框.多文本框.下拉列 ...

  6. 循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

    我们开发的系统,一般可以不用考虑语言国际化的问题,大多数系统一般是给本国人使用的,而且直接使用中文开发界面会更加迅速 一些,不过框架最好能够支持国际化的处理,以便在需要的时候,可以花点时间来实现多语言 ...

  7. 循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

    在我们做应用系统的时候,往往都会涉及图表的展示,综合的图表展示能够给客户带来视觉的享受和数据直观体验,同时也是增强客户认同感的举措之一.基于图表的处理,我们一般往往都是利用对应第三方的图表组件,然后在 ...

  8. 循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理

    VUE+Element 前端是一个纯粹的前端处理,前面介绍了很多都是Vue+Element开发的基础,从本章随笔开始,就需要进入深水区了,需要结合ABP框架使用(如果不知道,请自行补习一下我的随笔:A ...

  9. 循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

    在前面随笔<循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理>介绍了一个系统最初接触到的前端登录处理的实现,但往往对整个系统来说,一般会有很多业务对 ...

随机推荐

  1. 在Python实现print标准输出sys.stdout、stderr重定向及捕获的简单办法

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 Python中的标准输出和错误输出由sys模块的stdout.stde ...

  2. 第十九章、Model/View开发:QTableView的功能及属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 在Designer的部件栏Item Views中提供了PyQt和Qt已经实现好的table ...

  3. SpringCloud Alibaba学习笔记

    目录 目录 目录 导学 为什么学 学习目标 进阶目标 思路 Spring Cloud Alibaba的重要组件 环境搭建 Spring Boot必知必会 Spring Boot特性 编写第一个Spri ...

  4. selenium 淘宝商品分页

    通过这行代码确定每页的下一页,因为从淘宝的第4页 xpath就匹配不出下一页的位置#这是面向对象写法,不用的把self. 去掉即可next_button = self.driver.find_elem ...

  5. 【题解】「CF1373B」01 Game

    这题好水,就是简单的模拟+字符串. \(\sf Translation\) 给定一个 \(01\) 串,如果 \(0\) 出现的次数和 \(1\) 出现的次数的最小值是奇数,输出 DA ,否则输出 N ...

  6. Codeforces Edu Round 61 A-C + F

    A. Regular Bracket Sequence 显然,"\(()\)"不影响结果它是自我匹配的,可以把所有的\(((\)和\())\)都放在左边/右边,这样只要检查它们的数 ...

  7. win 7 MongoDB 下载安装

    准备: 1.mongodb-win32-x86_64-2008plus-ssl-3.4.3-signed.msi 官方下载 2.1.建立数据存放目录 F:\MongoDB\ 2.建立日志文件      ...

  8. sqli-labs less1-4(union注入)

    less-1 考点:Single quotes 输入: 判断类型 ?id=1 返回loginname和password.输入的id就是与后台数据库连接的接口通过id=? 查询数据库信息 ?id=1' ...

  9. Eureka系列(九)Eureka自我保护机制

      因为本篇简文并不是自己总结的,而是当了下搬运工,所以直接直接附上原作者博客链接. 参考链接:   1.SpringCloud Eureka自我保护机制   2.Spring Cloud Eurek ...

  10. Java字节码中对应的JDK版本

    Java class vs. JDK version mapping Java SE 9 = 53,Java SE 8 = 52,Java SE 7 = 51,Java SE 6.0 = 50,Jav ...