Store does not implement IUserLockoutStore

2020-03-10 05:53发布

问题:

I'm trying to implement own DAL for asp.net Identity 2.0 with functionality that I need. I don't need Account Lockout functionality. But When I try to call

var result = await SignInManager.PasswordSignInAsync(model.Login, model.Password, model.RememberMe, shouldLockout: false);

I get System.NotSupportedException:Store does not implement IUserLockoutStore<TUser>.

So why should I need to implement IUserLockoutStore if I dont need it?

回答1:

See this answer: When implementing your own IUserStore, are the "optional" interfaces on the class actually optional?

You will need to trick or override the method you are trying to call in your store to implement one that does not use the "optional" lockout store.

You may be unpleasantly surprised to find that you also need to implement the "optional" interface for two-factor. Use the same answer below to do so unless you do have a means of two-factor.

First, though, here's the default implementation:

public virtual async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
        {
           ...
            if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
            {
                return SignInStatus.LockedOut;
            }
            if (await UserManager.CheckPasswordAsync(user, password).WithCurrentCulture())
            {
                return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
            }
            ...
            return SignInStatus.Failure;
        }

One answer: create useless stores.

    #region LockoutStore
    public Task<int> GetAccessFailedCountAsync(MyUser user)
    {
        throw new NotImplementedException();
    }

    public Task<bool> GetLockoutEnabledAsync(MyUser user)
    {
        return Task.Factory.StartNew<bool>(() => false);
    }

    public Task<DateTimeOffset> GetLockoutEndDateAsync(MyUser user)
    {
        throw new NotImplementedException();
    }

    public Task<int> IncrementAccessFailedCountAsync(MyUser user)
    {
        throw new NotImplementedException();
    }

    public Task ResetAccessFailedCountAsync(MyUser user)
    {
        throw new NotImplementedException();
    }

    public Task SetLockoutEnabledAsync(MyUser user, bool enabled)
    {
        throw new NotImplementedException();
    }

    public Task SetLockoutEndDateAsync(MyUser user, DateTimeOffset lockoutEnd)
    {
        throw new NotImplementedException();
    }
    #endregion
}

Another solution: override to just not use it.

public virtual async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
        {
           ...
            if (false)
            {
                return SignInStatus.LockedOut;
            }
            if (await UserManager.CheckPasswordAsync(user, password).WithCurrentCulture())
            {
                return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
            }
            ...
            return SignInStatus.Failure;
        }

cf/ https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Owin/SignInManager.cs