myesn

myEsn2E9

hi
github

ABP: 使用手机号登录

首先参考 abp modules identity 源代码,在自己的 Web 项目中创建:

  • Pages/Account/Login.cshtml
  • Pages/Account/Login.cshtml.cs

先将 Login.cshtml 的源代码拷贝过来,然后修改 Login.cshtml.cs 文件的代码如下:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Volo.Abp.Account.Settings;
using Volo.Abp.Account.Web;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Settings;
using Volo.Abp.Validation;
using IdentityUser = Volo.Abp.Identity.IdentityUser;

namespace MiaoXin.Web.Pages.Account
{
    /// <summary>
    /// Volo.Abp.Account.Web.Pages.Account.LoginModel
    /// </summary>
    public class LoginModel : Volo.Abp.Account.Web.Pages.Account.LoginModel
    {
        // https://github.com/abpframework/abp/issues/8068#issuecomment-799981650
        private readonly IIdentityUserRepository _identityUserRepository;

        public LoginModel(
            IIdentityUserRepository identityUserRepository,
            IAuthenticationSchemeProvider schemeProvider,
            IOptions<AbpAccountOptions> accountOptions,
            IOptions<IdentityOptions> identityOptions,
            IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache
            )
            : base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache)
        {
            _identityUserRepository = identityUserRepository;
        }

        [BindProperty]
        public new LoginInputModel LoginInput { get; set; }

        // https://github.com/abpframework/abp/issues/7978#issuecomment-830715330
        public override async Task<IActionResult> OnPostAsync(string action)
        {
            //return base.OnPostAsync(action);
            await CheckLocalLoginAsync();

            ValidateModel();

            ExternalProviders = await GetExternalProviders();

            EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);

            await ReplacePhoneNumberToUsernameOfInputIfNeeds();
            await ReplaceEmailToUsernameOfInputIfNeeds();

            await IdentityOptions.SetAsync();

            var result = await SignInManager.PasswordSignInAsync(
                LoginInput.UserNameOrEmailAddressOrPhoneNumber,
                LoginInput.Password,
                LoginInput.RememberMe,
                true
            );

            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
            {
                Identity = IdentitySecurityLogIdentityConsts.Identity,
                Action = result.ToIdentitySecurityLogAction(),
                UserName = LoginInput.UserNameOrEmailAddressOrPhoneNumber
            });

            if (result.RequiresTwoFactor)
            {
                return await TwoFactorLoginResultAsync();
            }

            if (result.IsLockedOut)
            {
                Alerts.Warning(L["UserLockedOutMessage"]);
                return Page();
            }

            if (result.IsNotAllowed)
            {
                Alerts.Warning(L["LoginIsNotAllowed"]);
                return Page();
            }

            if (!result.Succeeded)
            {
                Alerts.Danger(L["InvalidUserNameOrPassword"]);
                return Page();
            }

            //TODO: Find a way of getting user's id from the logged in user and do not query it again like that!
            var user = await FindUserByPhoneNumberAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber) ??
                       await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber) ??
                       await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber);

            Debug.Assert(user != null, nameof(user) + " != null");

            // Clear the dynamic claims cache.
            await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);

            return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash);
        }

        protected override async Task ReplaceEmailToUsernameOfInputIfNeeds()
        {
            //return base.ReplaceEmailToUsernameOfInputIfNeeds();
            if (!ValidationHelper.IsValidEmailAddress(LoginInput.UserNameOrEmailAddressOrPhoneNumber))
            {
                return;
            }

            var userByUsername = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber);
            if (userByUsername != null)
            {
                return;
            }

            var userByEmail = await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber);
            if (userByEmail == null)
            {
                return;
            }

            LoginInput.UserNameOrEmailAddressOrPhoneNumber = userByEmail.UserName;
        }
        
        protected async Task ReplacePhoneNumberToUsernameOfInputIfNeeds()
        {
            // 手机号必须是 11 位数字
            if (!IsPhoneNumber(LoginInput.UserNameOrEmailAddressOrPhoneNumber))
            {
                return;
            }

            var userByPhoneNumber = await FindUserByPhoneNumberAsync(LoginInput.UserNameOrEmailAddressOrPhoneNumber);
            if (userByPhoneNumber == null)
            {
                return;
            }

            LoginInput.UserNameOrEmailAddressOrPhoneNumber = userByPhoneNumber.UserName;
        }

        /// <summary>
        /// 根据手机号查找用户
        /// https://stackoverflow.com/a/70344937
        /// </summary>
        /// <param name="phoneNumber"></param>
        /// <returns></returns>
        private async Task<IdentityUser?> FindUserByPhoneNumberAsync(string phoneNumber)
        {
            // https://github.com/abpframework/abp/issues/8068
            // UserManager.Users.FirstOrDefaultAsync(x => x.PhoneNumber == LoginInput.UserNameOrEmailAddressOrPhoneNumber);
            var identityUserDbSet = await _identityUserRepository.GetDbSetAsync();

            return await identityUserDbSet.FirstOrDefaultAsync(x => x.PhoneNumber == LoginInput.UserNameOrEmailAddressOrPhoneNumber);
        }


        /// <summary>
        /// 判断是否为手机号
        /// https://stackoverflow.com/a/29970789
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        private static bool IsPhoneNumber(string number)
        {
            return Regex.Match(number, @"^1[0-9]{10}$").Success;
        }


        public new class LoginInputModel
        {
            [Required]
            [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))]
            [DisplayName("用户名或手机号")]
            public string UserNameOrEmailAddressOrPhoneNumber { get; set; }

            [Required]
            [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
            [DataType(DataType.Password)]
            [DisableAuditing]
            [DisplayName("密码")]
            public string Password { get; set; }

            public bool RememberMe { get; set; }

            /// <summary>
            /// 图形验证码
            /// </summary>
            [Required]
            [StringLength(4)]
            [DisplayName("图形验证码")]
            public string Captcha { get; set; }
        }
    }
}
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.