Abp 实现通过手机号注册用户

前言

Abp 的 Identity 模块,实现了用户的管理,但是对于国内来讲,很多场景不能很好适配。比如:通过手机号进行注册的场景。

Abp vnext Identity 以及 asp.net core identity  默认只有 Email 必填以及唯一的校验,缺少手机号必要的校验;对此我们需要进行适当的调整,以作适配。

 

准备

 

建议先参考 IdentityUserAppService 对用户注册的实现;

由于手机号验证的场景基本上是需要的,所以本次采用重写的方式,当然也可以参考其代码,自定义自己的实现。

 

Application 

 public class PublicAccountAppService: IdentityUserAppService
    {
        public PublicAccountAppService(
            IdentityUserManager userManager,
            IIdentityUserRepository userRepository,
            IIdentityRoleRepository roleRepository,
            IOptions<IdentityOptions> identityOptions) 
            : base(userManager, userRepository, roleRepository, identityOptions)
        {

        }

        public override async Task<IdentityUserDto> CreateAsync(
            IdentityUserCreateDto input)
        {
            ValidateRegisterInput(input);
            await CheckRegisterableByPhone(input.PhoneNumber);
            return await base.CreateAsync(input);
        }

        private static void ValidateRegisterInput(IdentityUserCreateDto input)
        {
            if (input.PhoneNumber.IsNullOrWhiteSpace())
            {
                throw new AbpValidationException(
                    "Phone number is required for new users!",
                    new List<ValidationResult>
                    {
                        new ValidationResult(
                            "Phone number can not be empty!",
                            new []{"PhoneNumber"}
                        )
                    }
                );
            }
        }

        private async Task CheckRegisterableByPhone(string phoneNumber)
        {
            var isPhoneNumberExist = await _accountRepository.IsPhoneNumberExistAsync(phoneNumber);
            if (isPhoneNumberExist)
            {
                throw new AbpValidationException(
                    "Phone number already exist!",
                    new List<ValidationResult>
                    {
                        new ValidationResult(
                            "Phone number already exist!",
                            new []{"PhoneNumber"}
                        )
                    }
                );
            }
        }
    }

  

Domain

由于 IIdentityUserRepository 缺少对手机号是否存在的默认实现,我们可以新增对应Repository 来实现相关功能。

尽量遵守DDD 分层的原则。

1  public interface IAccountRepository
2     {
3         Task<bool> IsPhoneNumberExistAsync(string phoneNumber);
4     }

View Code

 

Repository

实现Domain 层定义的接口

 1  public class AccountRepository: IAccountRepository, ITransientDependency
 2     {
 3         private readonly IRepository<IdentityUser, Guid> _identityUserRepository;
 4 
 5         public AccountRepository(IRepository<IdentityUser, Guid> identityUserRepository)
 6         {
 7             _identityUserRepository = identityUserRepository;
 8         }
 9 
10         public async Task<bool> IsPhoneNumberExistAsync(string phoneNumber)
11         {
12             return await _identityUserRepository.AnyAsync(
13                 c => c.PhoneNumber == phoneNumber);
14         }
15     }

View Code

 

替换默认实例

我们已经完成了对 IdentityUserAppService 创建方法的重写,需要替换默认的接口实例对象,可以参考 Customizing Application Modules Overriding Services | Documentation Center | ABP.IO

    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IIdentityUserAppService), typeof(IdentityUserAppService), typeof(PublicAccountAppService))]
    public class PublicAccountAppService: IdentityUserAppService
    {...}

View Code

 

其他

主要的修改已经调整完毕。但是由于AbpUser 表没有 PhoneNumber 的相关索引,可以自行通过 Migration 进行添加。

Abp 框架比较优秀,很多方面也算是最佳实践,推荐使用。

改动比较小,修改起来也比较方便;当然也可以完全重写 注册的方法。下次有时间可以再整理下通过手机号登陆的实现。