Identity user manager find by phonenumber

Viewed 4719

In aspnet core identity2.0, Is there anyway to find a user by its phone number? The UserManager can find a user by its username and email, but there isn't a find by phone or even better, a generic find(Func<TUser, bool>) function provided. When user register with phone, need to check if a given phone number already existed, because a phone cannot be used by two users.

edit

start auth code:

services.AddIdentity<AccountUser, IdentityRole>()
            .AddEntityFrameworkStores<AccountDbContext>()
            .AddDefaultTokenProviders();
services.AddAuthentication().AddJwtBearer(...);
2 Answers

If you want to require unique Phone Numbers, you can do this in the ApplicationDbContext (or whatever context you are using as an IdentityDbContext) by adding this method:

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
    if (entityEntry != null && entityEntry.State == EntityState.Added)
    {
        var errors = new List<DbValidationError>();
        var user = entityEntry.Entity as ApplicationUser;
        //check for uniqueness of phone number
        if (user != null)
        {
            if (Users.Any(u => String.Equals(u.PhoneNumber, user.PhoneNumber)))
            {
                errors.Add(new DbValidationError("User",user.PhoneNumber+" is already registered."));
            }
        }
    }
    return base.ValidateEntity(entityEntry, items); //check for uniqueness of user name and email and return result
}

The inherited base.ValidateEntity method is what checks to make sure the UserName and Email are unique (if you've specified these options in the configuration).

For using statements it looks like you need:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

As for the exact question you asked: to access the Phone Numbers you need direct access to the data context. As far as I know neither UserManager nor even UserStore implement such a method, though you could define your own user store class inheriting from UserStore to add such a method.

Use this Code

UserStoreCustom.cs

 public class UserStoreCustom : UserStore<User>
    {
        public UserStoreCustom(ApplicationDbContext context, IdentityErrorDescriber describer = null)
            : base(context, describer)
        {

        }
        public virtual Task<User> FindByPhoneNumberAsync(string PhoneNumber, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            ThrowIfDisposed();
            return Users.FirstOrDefaultAsync(u => u.PhoneNumber == PhoneNumber, cancellationToken);
        }

Startup.cs

services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(configuration.GetConnectionString("DataCenter")));
   
            services.AddIdentity<User, IdentityRole>(option =>
            {
                // configure identity options
                option.Password.RequireDigit = false;
                option.Password.RequireLowercase = false;
                option.Password.RequireUppercase = false;
                option.Password.RequireNonAlphanumeric = false;
                option.Password.RequiredLength = 4;
                option.SignIn.RequireConfirmedPhoneNumber = true;
            })

                .AddRoles<IdentityRole>()
                .AddRoleManager<RoleManager<IdentityRole>>()
                 .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddUserStore<UserStoreCustom>()
                .AddDefaultTokenProviders();

            services.AddSingleton<UserStoreCustom>();
Related