8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能

时间:2021-11-07 04:35:38

  现在网站基本都用手机注册,很少用邮箱注册,本篇内容比较多,代码我会尽量加备注,有些操作需要连续添加几个文件才不报错,如果VS显示错误,请继续后续步骤。

前面已经有一篇文章讲到集成短信发送模块:http://www.cnblogs.com/shensigzs/category/1147235.html

在此基础上才能做手机注册功能,没有完成的同学请先去整合后再回来。

语言文件

AbpZeroTemplate-zh-CN.xml文件末尾添加如下键值对:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Core\Localization\AbpZeroTemplate\AbpZeroTemplate-zh-CN.xml

<text name="MobileRegister" value="手机注册" />
<text name="OccupiedMobilePhone" value="手机号码已注册或被占用" />
<text name="MobilePhone" value="手机号码" />

 

 

添加模型文件

在Web项目下Models\Account目录下添加MobileRegisterViewModel.cs,代码如下:

文件路径:D:\abpweb\PddSellerAssistant\PddSellerAssistant.Web\Models\Account\MobileRegisterViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using Abp.Auditing;
using MyCompanyName.AbpZeroTemplate.Authorization.Users;
using MyCompanyName.AbpZeroTemplate.Security;
using MyCompanyName.AbpZeroTemplate.Validation;
using MyCompanyName.AbpZeroTemplate.MultiTenancy;

namespace MyCompanyName.AbpZeroTemplate.Web.Models.Account
{
public class MobileRegisterViewModel : IValidatableObject
{
[StringLength(Tenant.MaxTenancyNameLength)]
public string TenancyName { get; set; }
/// <summary>
/// 手机号码
/// </summary>
[Required]
[StringLength(User.MaxMobilePhoneLength)]
public string MobilePhone { get; set; }

/// <summary>
/// 手机验证码
/// </summary>
[Required]
[StringLength(User.MobileCodeLength)]
public string MobilePhoneCode { get; set; }

[StringLength(User.MaxPlainPasswordLength)]
[DisableAuditing]
public string Password { get; set; }
public PasswordComplexitySetting PasswordComplexitySetting { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(MobilePhone))
{
if (new ValidationHelper().IsPhoneNumber(MobilePhone) == false)
{
yield return new ValidationResult("您输入的手机号码无效 !");
}
}
else
{
yield return new ValidationResult("手机号码不能为空 !");
}
}
}
}

 

Core项目

User.cs类添加如下代码:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Core\Authorization\Users\User.cs

public const int MaxMobilePhoneLength = 11;
public const int MobileCodeLength = 6;

 

再打开ValidationHelper.cs,添加如下代码:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Core\Validation\ValidationHelper.cs

/// <summary>
/// 验证手机号是否有效
/// </summary>
/// <param name="phoneNumber"></param>
/// <returns></returns>
public bool IsPhoneNumber(string phoneNumber)
{
if (string.IsNullOrWhiteSpace(phoneNumber))
{
return false;
}
string pattern = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$";
return Regex.IsMatch(phoneNumber, pattern);

}

 

 UserStore.cs类添加如下代码:

文件路径:D:\abpweb\PddSellerAssistant\PddSellerAssistant.Core\Authorization\Users\UserStore.cs

private readonly IRepository<User, long> _userRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;

 

 _userRepository = userRepository;
_unitOfWorkManager
= unitOfWorkManager;
#region 扩展方法
/// <summary>
/// 按手机号码查询用户
/// </summary>
/// <param name="phoneNumber"></param>
/// <returns></returns>
public virtual async Task<User> FindByPhoneNumberAsync(string phoneNumber)
{

return await _userRepository.FirstOrDefaultAsync(
user
=> user.PhoneNumber == phoneNumber
);
}

[UnitOfWork]
public virtual async Task<User> FindByPhoneNumberAsync(int? tenantId, string phoneNumber)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return await FindByPhoneNumberAsync(phoneNumber);
}
}
#endregion

 

AbpZeroTemplateConsts.cs添加如下代码:

文件路径:D:\abpweb\PddSellerAssistant\PddSellerAssistant.Core\AbpZeroTemplateConsts.cs

#region 手机短信模板
/// <summary>
/// 手机短信验证码通用模板
/// </summary>
public const string SmsTemplateCommonCode = "SMS_119088461";
#endregion

 

UserManager.cs 重写CreateAsync、CheckDuplicateUsernameOrEmailAddressAsync方法,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Core\Authorization\Users\UserManager.cs

public override async Task<IdentityResult> CreateAsync(User user)
{
var result = await CheckDuplicateUsernameOrEmailAddressAsync(user.Id, user.UserName, user.EmailAddress);
if (!result.Succeeded)
{
return result;
}
if (string.IsNullOrWhiteSpace(user.EmailAddress))
{
user.EmailAddress
= string.Empty;
}


var tenantId = GetCurrentTenantId();
if (tenantId.HasValue && !user.TenantId.HasValue)
{
user.TenantId
= tenantId.Value;
}

try
{
return await base.CreateAsync(user);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}

}

public override async Task<IdentityResult> CheckDuplicateUsernameOrEmailAddressAsync(long? expectedUserId, string userName, string emailAddress)
{
var user = (await FindByNameAsync(userName));
if (user != null && user.Id != expectedUserId)
{
return AbpIdentityResult.Failed(string.Format(L("Identity.DuplicateName"), userName));
}


return IdentityResult.Success;
}

private int? GetCurrentTenantId()
{
if (_unitOfWorkManager.Current != null)
{
return _unitOfWorkManager.Current.GetTenantId();
}

return AbpSession.TenantId;
}

private string L(string name)
{
return LocalizationManager.GetString(AbpZeroConsts.LocalizationSourceName, name);
}

 

Application项目 

MyAbpLoginResultType.cs添加这个类,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Application\Authorization\MyAbpLoginResultType.cs

namespace MyCompanyName.AbpZeroTemplate.Authorization
{
public enum MyAbpLoginResultType : byte
{
/// <summary>
/// 手机号码未验证
/// </summary>
UserMobilePhoneNotConfirmed = 10
}
}

 

 

LogInManager.cs扩展这个类,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Application\Authorization\LogInManager.cs

private readonly IMultiTenancyConfig _multiTenancyConfig;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IRepository<Tenant> _tenantRepository;
private readonly AbpUserManager<Role, User> _userManager;
private readonly UserStore _userStore;

 

public LogInManager(
UserManager userManager,
IMultiTenancyConfig multiTenancyConfig,
IRepository
<Tenant> tenantRepository,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IRepository
<UserLoginAttempt, long> userLoginAttemptRepository,
IUserManagementConfig userManagementConfig,
IIocResolver iocResolver,
RoleManager roleManager,
UserStore userStore)
:
base(
userManager,
multiTenancyConfig,
tenantRepository,
unitOfWorkManager,
settingManager,
userLoginAttemptRepository,
userManagementConfig,
iocResolver,
roleManager)
{
_multiTenancyConfig
= multiTenancyConfig;
_unitOfWorkManager = unitOfWorkManager;
_tenantRepository = tenantRepository;
_userManager = userManager;
_userStore =
userStore;
}

 

public virtual async Task<AbpLoginResult<Tenant, User>> LoginByMobileAsync(string mobilePhone, string plainPassword, string tenancyName = null,
bool shouldLockout = true)
{
var result = await LoginByMobileAsyncInternal(mobilePhone, plainPassword, tenancyName, shouldLockout);
await SaveLoginAttempt(result, tenancyName, mobilePhone);
return result;
}

protected async Task<AbpLoginResult<Tenant, User>> LoginByMobileAsyncInternal(string mobilePhone, string plainPassword, string tenancyName, bool shouldLockout)
{
if (mobilePhone.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(mobilePhone));
}

if (plainPassword.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(plainPassword));
}

//Get and check tenant
Tenant tenant = null;
using (_unitOfWorkManager.Current.SetTenantId(null))
{
if (!_multiTenancyConfig.IsEnabled)
{
tenant
= await GetDefaultTenantAsync();
}
else if (!string.IsNullOrWhiteSpace(tenancyName))
{
tenant
= await _tenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenancyName);
if (tenant == null)
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidTenancyName);
}

if (!tenant.IsActive)
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.TenantIsNotActive, tenant);
}
}
}

var tenantId = tenant == null ? (int?)null : tenant.Id;
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
var user = await _userStore.FindByPhoneNumberAsync(tenantId, mobilePhone);
if (user == null)
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidUserNameOrEmailAddress, tenant);
}

_userManager.InitializeLockoutSettings(tenantId);

if (await _userManager.IsLockedOutAsync(user.Id))
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.LockedOut, tenant, user);
}

var verificationResult = _userManager.PasswordHasher.VerifyHashedPassword(user.Password, plainPassword);
if (verificationResult != PasswordVerificationResult.Success)
{
if (shouldLockout)
{
if (await TryLockOutAsync(tenantId, user.Id))
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.LockedOut, tenant, user);
}
}

return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidPassword, tenant, user);
}

await _userManager.ResetAccessFailedCountAsync(user.Id);

return await CreateLoginByMobileResultAsync(user, tenant);
}
}

protected async Task<AbpLoginResult<Tenant, User>> CreateLoginByMobileResultAsync(User user, Tenant tenant = null)
{
if (!user.IsActive)
{
return new AbpLoginResult<Tenant, User>(AbpLoginResultType.UserIsNotActive);
}

if (!user.IsPhoneNumberConfirmed)
{
return new AbpLoginResult<Tenant, User>((AbpLoginResultType)MyAbpLoginResultType.UserMobilePhoneNotConfirmed);
}

user.LastLoginTime
= Clock.Now;

await _userManager.AbpStore.UpdateAsync(user);

await _unitOfWorkManager.Current.SaveChangesAsync();

return new AbpLoginResult<Tenant, User>(
tenant,
user,
await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie)
);
}

 

 

Web项目

CodeHelper.cs添加此类,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Helpers\CodeHelper.cs

/// <summary>
/// 生成6位手机验证码
/// </summary>
/// <returns></returns>
public static string SetNewPhoneCode()
{
var c = RandomHelper.GetRandom(100000, 999999);
return c + "";
}

 

AccountController.cs添加如下代码,大概351行位置:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Controllers\AccountController.cs

/// <summary>
/// 手机注册
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public ActionResult RegisterByMobile()
{
return MobileRegisterView(new MobileRegisterViewModel
{
TenancyName
= _tenancyNameFinder.GetCurrentTenancyNameOrNull(),
PasswordComplexitySetting
= JsonConvert.DeserializeObject<PasswordComplexitySetting>(SettingManager.GetSettingValue(AppSettings.Security.PasswordComplexity))
});

}

public ActionResult MobileRegisterView(MobileRegisterViewModel model)
{
CheckSelfRegistrationIsEnabled();

ViewBag.IsMultiTenancyEnabled
= _multiTenancyConfig.IsEnabled;

return View("RegisterByMobile", model);
}

 

 [HttpPost]
[UnitOfWork]
public virtual async Task<ActionResult> RegisterByMobile(MobileRegisterViewModel model)
{
try
{

CheckSelfRegistrationIsEnabled();
VaildateMobile(model.MobilePhoneCode);
//判断手机号是否被占用
var ur = await _userManager.Users.Where(
u
=> u.PhoneNumber == model.MobilePhone
).FirstOrDefaultAsync();
if (ur != null)
{
throw new UserFriendlyException(L("OccupiedMobilePhone"));
}

if (!_multiTenancyConfig.IsEnabled)
{
model.TenancyName
= Tenant.DefaultTenantName;
}
else if (model.TenancyName.IsNullOrEmpty())
{
throw new UserFriendlyException(L("TenantNameCanNotBeEmpty"));
}

CurrentUnitOfWork.SetTenantId(
null);

var tenant = await GetActiveTenantAsync(model.TenancyName);

CurrentUnitOfWork.SetTenantId(tenant.Id);

if (!await SettingManager.GetSettingValueForTenantAsync<bool>(AppSettings.UserManagement.AllowSelfRegistration, tenant.Id))
{
throw new UserFriendlyException(L("SelfUserRegistrationIsDisabledMessage_Detail"));
}

await _userPolicy.CheckMaxUserCountAsync(tenant.Id);

//Getting tenant-specific settings
var isNewRegisteredUserActiveByDefault = await SettingManager.GetSettingValueForTenantAsync<bool>(AppSettings.UserManagement.IsNewRegisteredUserActiveByDefault, tenant.Id);
var isEmailConfirmationRequiredForLogin = await SettingManager.GetSettingValueForTenantAsync<bool>(AbpZeroSettingNames.UserManagement.IsEmailConfirmationRequiredForLogin, tenant.Id);

var user = new User
{
TenantId
= tenant.Id,
IsActive
= isNewRegisteredUserActiveByDefault,
PhoneNumber
= model.MobilePhone,
IsPhoneNumberConfirmed
= true
};

ExternalLoginInfo externalLoginInfo
= null;
//用户名或密码为空,抛出异常
if (model.MobilePhone.IsNullOrEmpty() || model.Password.IsNullOrEmpty())
{
throw new UserFriendlyException(L("FormIsNotValidMessage"));
}

user.UserName
= model.MobilePhone;
user.Password
= new PasswordHasher().HashPassword(model.Password);

user.Roles
= new List<UserRole>();
foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync())
{
user.Roles.Add(
new UserRole(tenant.Id, user.Id, defaultRole.Id));
}

CheckErrors(
await _userManager.CreateAsync(user));
await _unitOfWorkManager.Current.SaveChangesAsync();


//通知
await _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync(user.ToUserIdentifier());
await _appNotifier.WelcomeToTheApplicationAsync(user);
await _appNotifier.NewUserRegisteredAsync(user);

//如果可能,直接登录
if (user.IsActive && user.IsPhoneNumberConfirmed)
{
AbpLoginResult
<Tenant, User> loginResult;
loginResult
= await GetLoginByMobileResultAsync(user.UserName, model.Password, tenant.TenancyName);

if (loginResult.Result == AbpLoginResultType.Success)
{
await SignInAsync(loginResult.User, loginResult.Identity);

return Redirect(Url.Action("Index", "Application"));
}

Logger.Warn(
"新注册的用户无法登录。 这不应该是正常。 登录结果: " + loginResult.Result);
}

return View("RegisterResult", new RegisterResultViewModel
{
TenancyName
= tenant.TenancyName,
NameAndSurname
= user.Name + " " + user.Surname,
UserName
= user.UserName,
EmailAddress
= user.EmailAddress,
IsActive
= user.IsActive,
IsEmailConfirmationRequired
= isEmailConfirmationRequiredForLogin
});
}
catch (UserFriendlyException ex)
{
ViewBag.IsMultiTenancyEnabled
= _multiTenancyConfig.IsEnabled;
ViewBag.UseCaptcha
= UseCaptchaOnRegistration();
ViewBag.ErrorMessage
= ex.Message;
ViewBag.ErrorDetails
= ex.Details;

return View("RegisterByMobile", model);
}
}

 

 

/// <summary>
/// 手机验证码验证
/// </summary>
/// <param name="mobilePhoneCode"></param>
private void VaildateMobile(string mobilePhoneCode)
{
if (mobilePhoneCode.Length != Authorization.Users.User.MobileCodeLength)
{
throw new UserFriendlyException(string.Format("验证码必须为 {0} 位!", Authorization.Users.User.MobileCodeLength));
}
//手机验证码效验
var phoneCode = Session["PhoneCode"];
var now = Session["PhoneCodeDateTime"];
if (phoneCode == null || string.IsNullOrWhiteSpace(phoneCode.ToString()))
{
throw new UserFriendlyException("您输入的验证码无效!");
}
var nowTime = Convert.ToDateTime(now);
var t = DateTime.Now - nowTime;
if (t.TotalSeconds >= 180)
{
throw new UserFriendlyException("您输入的验证码无效!");
}
if (!mobilePhoneCode.Equals(phoneCode.ToString()))
{
throw new UserFriendlyException("您输入的验证码不正确!");
}
}

private async Task<AbpLoginResult<Tenant, User>> GetLoginByMobileResultAsync(string mobilePhone, string password, string tenancyName)
{
var loginResult = await _logInManager.LoginByMobileAsync(mobilePhone, password, tenancyName);

switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, mobilePhone, tenancyName);
}
}

 

VerificationCodeController.cs添加此控制器,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Controllers\VerificationCodeController.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Abp.Net.Sms;
using Abp.UI;
using MyCompanyName.AbpZeroTemplate.Authorization.Users;
using MyCompanyName.AbpZeroTemplate.MultiTenancy;
using MyCompanyName.AbpZeroTemplate.Validation;
using MyCompanyName.AbpZeroTemplate.Web.Helpers;

namespace MyCompanyName.AbpZeroTemplate.Web.Controllers
{
public class VerificationCodeController : AbpZeroTemplateControllerBase
{
private readonly UserManager _userManager;
private readonly ISmsSender _smsSender;
private readonly TenantManager _tenantManager;
private readonly IUserEmailer _userEmailer;

public VerificationCodeController(UserManager userManager,
ISmsSender smsSender,
TenantManager tenantManager,
IUserEmailer userEmailer)
{
_userManager
= userManager;
_smsSender
= smsSender;
_tenantManager
= tenantManager;
_userEmailer
= userEmailer;
}
#region 手机

/// <summary>
/// 注册时使用,发送手机验证码
/// </summary>
/// <param name="phoneNumber"></param>
/// <returns></returns>
[HttpPost]
public async Task<JsonResult> SendMobileCode(string phoneNumber)
{
try
{
if (!new ValidationHelper().IsPhoneNumber(phoneNumber))
{
throw new UserFriendlyException("您输入了无效的手机号码!");
}
//检查手机是否已被注册
var user = await _userManager.Users.Where(
u
=> u.PhoneNumber == phoneNumber
).FirstOrDefaultAsync();

if (user != null)
{
throw new UserFriendlyException(L("OccupiedMobilePhone"));
}
//生成6位数字验证码
var code = CodeHelper.SetNewPhoneCode();
//发送验证码
await _smsSender.SendAsync(phoneNumber, AbpZeroTemplateConsts.SmsTemplateCommonCode, "{\"code\":\"" + code + "\"}");
//存储验证码、手机号、时间,以备验证使用
Session["PhoneCode"] = code;
Session[
"PhoneNumber"] = phoneNumber;
Session[
"PhoneCodeDateTime"] = DateTime.Now;
return Json("OK", JsonRequestBehavior.DenyGet);
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
}



/// <summary>
///验证手机时使用,发送手机验证码
/// </summary>
/// <param name="phoneNumber"></param>
/// <returns></returns>
[HttpPost]
public async Task<JsonResult> SendMobileCodeByVerificationMobile(string phoneNumber)
{
try
{
if (!new ValidationHelper().IsPhoneNumber(phoneNumber))
{
throw new UserFriendlyException("您输入了无效的手机号码!");
}
//检查手机是否已被注册
var user = await _userManager.Users.Where(
u
=> u.PhoneNumber == phoneNumber && u.Id != AbpSession.UserId
).FirstOrDefaultAsync();

if (user != null)
{
throw new UserFriendlyException(L("OccupiedMobilePhone"));
}
//生成6位数字验证码
var code = CodeHelper.SetNewPhoneCode();
//发送验证码
await _smsSender.SendAsync(phoneNumber, AbpZeroTemplateConsts.SmsTemplateCommonCode, "{\"code\":\"" + code + "\"}");
//存储验证码、手机号、时间,以备验证使用
Session["PhoneCode"] = code;
Session[
"PhoneNumber"] = phoneNumber;
Session[
"PhoneCodeDateTime"] = DateTime.Now;
return Json("OK", JsonRequestBehavior.DenyGet);
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
}

#endregion

#region private
/// <summary>
/// 检查手机号码是否已被注册,未注册抛出异常
/// </summary>
/// <param name="mobilePhone"></param>
/// <returns></returns>
private async Task<User> GetUserByCheckingMobile(string mobilePhone)
{
var user = await _userManager.Users.Where(
u
=> u.PhoneNumber == mobilePhone
).FirstOrDefaultAsync();

if (user == null)
{
throw new UserFriendlyException(L("InvalidMobilePhone"));
}

return user;
}

#endregion
}
}

 

添加视图

添加RegisterByMobile.cshtml视图文件,代码如下:

文件路径:D:\abpweb\PddSellerAssistant\PddSellerAssistant.Web\Views\Account\RegisterByMobile.cshtml

@model MyCompanyName.AbpZeroTemplate.Web.Models.Account.MobileRegisterViewModel
@using System.Web.Script.Serialization
@using Abp.Extensions
@using Abp.Web.Mvc.Extensions
@using MyCompanyName.AbpZeroTemplate.MultiTenancy
@using Recaptcha.Web
@using Recaptcha.Web.Mvc
@section Scripts
{
<script>
window.passwordComplexitySetting
= @(new JavaScriptSerializer().Serialize(Model.PasswordComplexitySetting).Replace("\"", ""));
</script>
@Html.IncludeScript("~/Views/Account/RegisterByMobile.js")
}
<form class="register-form" action="@Url.Action("RegisterByMobile")" method="post">

<h3>@L("MobileRegister")</h3>

@if (@ViewBag.ErrorMessage != null)
{
<div class="alert alert-danger">
<i class="fa fa-warning"></i> @ViewBag.ErrorMessage
@if (@ViewBag.ErrorDetails != null)
{
<br />@ViewBag.ErrorDetails
}
</div>
}

@Html.AntiForgeryToken()

@if (ViewBag.IsMultiTenancyEnabled)
{
if (Model.TenancyName.IsNullOrEmpty())
{
<p class="hint">
@L("TenantInformations")
</p>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("TenancyName")</label>
<input class="form-control placeholder-no-fix input-ltr" type="text" placeholder="@L("TenancyName")" name="TenancyName" value="@(Model.TenancyName ?? "")" required maxlength="@Tenant.MaxTenancyNameLength" />
</div>
}
else
{
<input type="hidden" name="TenancyName" value="@Model.TenancyName" />
}
}

<p class="hint">
@L("AccountSettings")
</p>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("MobilePhone")</label>
<input class="form-control placeholder-no-fix" type="text" placeholder="@L("MobilePhone")" id="MobilePhone" name="MobilePhone" required value="@Model.MobilePhone" maxlength="@MyCompanyName.AbpZeroTemplate.Authorization.Users.User.MaxMobilePhoneLength" />
</div>
<div class="form-group">
<div class="input-group input-group-lg">

<div class="input-group-control">
<input type="text" class="form-control input-sm" autocomplete="off" id="MobileCode" name="MobilePhoneCode" value="" required placeholder="验证码">
</div>
<span class="input-group-btn btn-right">
<button id="SendMobileCode" class="btn green-haze" type="button">发送验证码</button>
</span>
</div>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("Password")</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" id="RegisterPassword" placeholder="@L("Password")" name="Password" required />
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("PasswordRepeat")</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="@L("PasswordRepeat")" name="PasswordRepeat" required />
</div>


<div class="form-actions">
<a href="@Url.Action("Login", "Account")"><button type="button" id="register-back-btn" class="btn btn-default">@L("Back")</button></a>
<a href="@Url.Action("Register","Account")">邮箱注册</a>
<button type="submit" id="register-submit-btn" class="btn btn-success uppercase pull-right">@L("Submit")</button>
</div>
</form>

 

 

JS文件

添加一个跟视图名称一样的JS文件 RegisterByMobile.js,代码如下:

 文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Views\Account\RegisterByMobile.js

var CurrentPage = function () {

jQuery.validator.addMethod(
"customUsername", function (value, element) {
if (value === $('input[name="MobilePhoneCode"]').val()) {
return true;
}

return !$.validator.methods.email.apply(this, arguments);
}, abp.localization.localize(
"RegisterFormUserNameInvalidMessage"));

var _passwordComplexityHelper = new app.PasswordComplexityHelper();

var handleRegister = function () {

$(
'.register-form').validate({
rules: {
PasswordRepeat: {
equalTo:
"#RegisterPassword"
},
MobilePhone: {
required:
true,
},
MobileCode: {
required:
true,
}
},

submitHandler:
function (form) {
form.submit();
}
});

var $element = $('#RegisterPassword');
_passwordComplexityHelper.setPasswordComplexityRules($element, window.passwordComplexitySetting);
/**
发送验证码
*/
$(sendMobileCodeBtn).click(
function () {
var phoneNumber = $("#MobilePhone").val();
if (checkMobile(phoneNumber) == false) {
return false;
}

curCount
= count;
abp.ajax({
contentType: app.consts.contentTypes.formUrlencoded,
url:
'/VerificationCode/SendMobileCode',
data: { phoneNumber: phoneNumber }
}).done(
function (result) {
if (result.result == "OK") {
// 设置按钮显示效果,倒计时
$(sendMobileCodeBtn).attr("disabled", "true");
$(sendMobileCodeBtn).text(
"请在" + curCount + "秒内输入验证码");
InterValObj
= window.setInterval(SetRemainTime, 1000); // 启动计时器,1秒执行一次
} else {
$(sendMobileCodeBtn).val(
"重新发送验证码");
}
});
});


}

return {
init:
function () {
handleRegister();
}
};

}();
var InterValObj; //timer变量,控制时间
var count = 60 * 3; //间隔函数,1秒执行
var curCount;//当前剩余秒数
var codeLength = 6;//验证码长度
var sendMobileCodeBtn = $("#SendMobileCode");
//timer处理函数
function SetRemainTime() {
if (curCount == 0) {
window.clearInterval(InterValObj);
// 停止计时器
$(sendMobileCodeBtn).removeAttr("disabled");// 启用按钮
$(sendMobileCodeBtn).text("重新发送验证码");
code
= ""; // 清除验证码。如果不清除,过时间后,输入收到的验证码依然有效
} else {
curCount
--;
$(sendMobileCodeBtn).text(
"请在" + curCount + "秒内输入验证码");
}
}

function checkMobile(phone) {
if (!(/^1[3|4|5|8][0-9]\d{4,8}$/.test(phone))) {
abp.message.error(
'您输入了无效的手机号', '错误');
return false;
}
}

 

 手机注册入口

 Register.cshtml添加手机号注册连接,代码如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Views\Account\Register.cshtml

<div class="form-actions">
<a href="@Url.Action("Login", "Account")"><button type="button" id="register-back-btn" class="btn btn-default">@L("Back")</button></a>
<a href="@Url.Action("RegisterByMobile","Account")">手机号注册</a>
<button type="submit" id="register-submit-btn" class="btn btn-success uppercase pull-right">@L("Submit")</button>
</div>

 

 保存生成项目,浏览器打开注册页面,如下图所示:

8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能

 

8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能

 

8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能

 

8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能

 

注册成功会自动登录系统,此时注销用户,再次登录会提示“登录失败”,接下来修改登录功能,使之同时支持手机、邮箱、用户名登录。

 

登录功能修改

AccountController.cs修改Login Post方法,143行位置代码修改如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Web\Controllers\AccountController.cs

 

AbpLoginResult<Tenant,
Authorization.Users.User
> loginResult = null;
if (new ValidationHelper().IsPhoneNumber(loginModel.UsernameOrEmailAddress))
{
loginResult
=
await
GetLoginByMobileResultAsync(loginModel.UsernameOrEmailAddress, loginModel.Password,
loginModel.TenancyName);
}
else
{
loginResult
= await GetLoginResultAsync(loginModel.UsernameOrEmailAddress, loginModel.Password, loginModel.TenancyName);
}

 

 

AbpZeroTemplate-zh-CN.xml ,代码修改如下:

文件路径:D:\abp version\aspnet-zero-3.4.0\aspnet-zero-3.4.0\src\MyCompanyName.AbpZeroTemplate.Core\Localization\AbpZeroTemplate\AbpZeroTemplate-zh-CN.xml  

<text name="UserNameOrEmail" value="手机或用户名或邮箱地址" />

 

 

 生成项目,再次以手机、邮箱、用户名登录,已经都可以正常登录。

手机注册登录功能到这里修改完成,篇幅很多,基本把整个解决方案翻了一篇。

 

 返回总目录