交流QQ号:555913397
有什么问题可以加群大家一起交流
Abp Core 添加短信验证码登录(动态密码登录)
现目前我国网站的已经很少使用电子邮箱了,基本上都是手机号作为账号,有时候粗心的用户会忘记密码,网站就提供了更方便的短信验证码登录.使用短信验证码来替代密码,本小白也想实现这个功能,但是Abp并没有提供这样的方法,于是经过不懈努力,终于搞定了,废话不多说下面上代码.
1.添加通过手机号查询用户方法
在Core\Authorization\Users\UserStore.cs
///
/// 通过手机号查询用户
///
/// 手机号
///
public virtual async Task FindByPhoneNumberAsync(string phoneNumber)
{
return await _userRepository.FirstOrDefaultAsync(model => model.PhoneNumber == phoneNumber);
}
///
/// 通过手机号查询用户
///
/// 租户id
/// 手机号
///
[UnitOfWork]
public virtual async Task FindByPhoneNumberAsync(int? tenantId, string phoneNumber)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return await FindByPhoneNumberAsync(phoneNumber);
}
}
2.添加验证码效验方法
在Core\Authorization\Users\UserManager.cs
///
/// 检查验证码
///
/// 用户
/// 验证码
///
public virtual async Task<bool> CheckCaptcha(User user, int captcha)
{
var entity = await _smsCaptchaRepository.FirstOrDefaultAsync(model => model.PhoneNumer == user.PhoneNumber);
if (entity.Captcha == captcha)
return true;
return false;
}
3.添加手机验证码登录功能
在Core\Authorization\LoginManager.cs
手机验证码登陆
///
/// 手机验证码登陆
///
/// 手机号
/// 验证码
/// 租户名
/// 是否锁定
///
public virtual async Task> LoginByMobileAsync(string phoneNumber, int captcha,
string tenantName = null, bool shouldLockout = true)
{
var result = await LoginByMobileAsyncInternal(phoneNumber, captcha, tenantName, shouldLockout);
await SaveLoginAttempt(result, tenantName, result.User.UserName);
return result;
}
手机验证码登陆内部方法
///
/// 手机验证码登陆内部方法
///
/// 手机号
/// 验证码
/// 租户名
/// 是否锁定
///
protected virtual async Task> LoginByMobileAsyncInternal(string phoneNumber,
int captcha, string tenantName, bool shouldLockout)
{
if (phoneNumber.IsNullOrEmpty())
{
Logger.Error("手机号不能为空");
throw new UserFriendlyException("手机号不能为空");
}
//获取和检查租户
Tenant tenant = null;
//设置当前租户id为空
using (_unitOfWorkManager.Current.SetTenantId(null))
{
//如果关闭租户就获取默认租户
if (!_multiTenancyConfig.IsEnabled)
{
//获取默认租户
tenant = await GetDefaultTenantAsync();
}
//租户id是否为空
else if (!string.IsNullOrWhiteSpace(tenantName))
{
//查询租户信息
tenant = await _tenantRepository.FirstOrDefaultAsync(model => model.TenancyName == tenantName);
if (tenant == null)
//返回无效租户
return new AbpLoginResult(AbpLoginResultType.InvalidTenancyName);
if (!tenant.IsActive)
//返回租户未启用
return new AbpLoginResult(AbpLoginResultType.TenantIsNotActive, tenant);
}
}
//设置租户id
var tenantId = tenant == null ? (int?)null : tenant.Id;
//设置当前租户id
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
//初始化选项
await _userManager.InitializeOptionsAsync(tenantId);
var loggedInFromExternalSource = false;
//通过手机号查询用户
var user = await _userStore.FindByPhoneNumberAsync(tenantId, phoneNumber);
if (user == null)
//返回无效用户
return new AbpLoginResult(AbpLoginResultType.InvalidUserNameOrEmailAddress, tenant);
//用户是否被锁定
if (await _userManager.IsLockedOutAsync(user))
//返回锁定用户
return new AbpLoginResult(AbpLoginResultType.LockedOut, tenant, user);
if (!loggedInFromExternalSource)
{
if (!await _userManager.CheckCaptcha(user, captcha))
{
//是否锁定
if (shouldLockout)
{
//锁定账户
if (await TryLockOutAsync(tenantId, user.Id))
//返回锁定账户
return new AbpLoginResult(AbpLoginResultType.LockedOut, tenant, user);
}
//返回无效密码
return new AbpLoginResult(AbpLoginResultType.InvalidPassword, tenant, user);
}
//重置登陆失败次数
await UserManager.ResetAccessFailedCountAsync(user);
}
return await CreateLoginByMobileResultAsync(user, tenant);
}
}
创建手机号登陆结果
///
/// 创建手机号登陆结果
///
/// 用户
/// 租户
///
protected virtual async Task> CreateLoginByMobileResultAsync(User user,
Tenant tenant = null)
{
//用户未激活
if (!user.IsActive)
//返回用户未激活
return new AbpLoginResult(AbpLoginResultType.UserIsNotActive, tenant, user);
//用户手机号未认证
if (user.IsPhoneNumberConfirmed)
//返回用户手机号未认证
return new AbpLoginResult(AbpLoginResultType.UserPhoneNumberIsNotConfirmed, tenant, user);
user.LastLoginTime = Clock.Now;
//更新用户
await _userManager.UpdateAsync(user);
await _unitOfWorkManager.Current.SaveChangesAsync();
var principal = await _claimsPrincipalFactory.CreateAsync(user);
return new AbpLoginResult(
tenant,
user,
principal.Identity as ClaimsIdentity
);
}
添加webApi
在web.core\Controllers\TokenAuthController.cs
通过手机验证码授权
///
/// 通过手机验证码授权
///
/// 手机验证码Dto
///
[HttpPost]
public async Task AuthenticateByPhoneCaptcha([FromBody] AuthenticateByPhoneCaptchaModel model)
{
var loginResult = await GetLoginResultByPhoneCaptchaAsync(
model.PhoneNumber,
model.Captcha,
GetTenancyNameOrNull()
);
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
** 获取登陆结果通过手机验证码**
///
/// 获取登陆结果通过手机验证码
///
/// 手机号
/// 验证码
/// 租户名
///
private async Task> GetLoginResultByPhoneCaptchaAsync(string phoneNumber, int 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);
}
}
至此大工告成,还有手机号登录,将在下一篇文章讲解.代码上有详细注解,有什么不懂的可以加QQ群大家交流.