循序漸進VUE+Element 前端應用開發(32)--- 手機簡訊動態碼登陸處理
- 2021 年 1 月 6 日
- 筆記
- 循序漸進VUE+Element
在一些系統中,有時候用戶忘記密碼,可以通過向自己手機發送動態驗證碼的方式實現系統登錄功能。本篇隨筆介紹如何結合後端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)
})
})
},
在登錄介面中,輸入動態碼登錄即可順利進入系統,和常規的處理一樣。

以上就是參照常規帳號密碼登錄的方式,構建一個動態碼登錄的處理,流程還是差不多,不過整合了簡訊發送,快取處理,帳號登陸等幾個流程,可以作為一個簡單的系統登錄過程的了解。

