自定义ASP.NET Identity 2.0 UserStore - 是否实现了所需的所有接口?

Ste*_*ins 18 c# asp.net asp.net-identity-2

IUserStore<TUser,int>为我的应用程序创建了一个自定义.我已经实现了我需要的接口,

   IUserStore<TUser, int>,
   IUserRoleStore<TUser, int>,
   IUserLockoutStore<TUser, int>,
   IUserPasswordStore<TUser, int>
Run Code Online (Sandbox Code Playgroud)

但是当我打电话的时候

var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
Run Code Online (Sandbox Code Playgroud)

我得到一个例外说法

Store does not implement IUserTwoFactorStore<TUser>.
Run Code Online (Sandbox Code Playgroud)

我在我的应用程序中没有使用双因素身份验证.为什么它希望我实现该接口?是否需要实现所有这些接口,即使我实际上没有使用它们?

Ign*_*nia 16

实际上IUserTwoFactorStore界面非常简单,到目前为止我的实现(我也不使用两个因子身份验证)是这样的:

 ....
 public Task<bool> GetTwoFactorEnabledAsync(User user)
 {
     return Task.FromResult(false);
 }

 public Task SetTwoFactorEnabledAsync(User user, bool enabled)
 {
     throw new NotImplementedException();
 }
Run Code Online (Sandbox Code Playgroud)

虽然我刚刚在几分钟前完成它并且没有彻底测试整个应用程序,但它确实有效.

  • 是的,这会奏效,但它非常讨厌.它杀死了liskov替代原则.我认为可以肯定地说,不检查IUserTwoFactorStore实现是Identity类的Identity中的设计缺陷. (9认同)

Gui*_*rte 14

我有同样的问题.目前,当SignInManager.SignInOrTwoFactor方法盲目地检查GetTwoFactorAuthentication时,它会在UserStore未实现IUserTwoFactorStore时抛出异常.

我相信Microsoft打算在自定义SignInManager类中重写SignInManager PasswordSignInAsync方法.不幸的是,我找不到任何文档或样本.

这是我为解决此问题而实现的SignInManager包装类:

public class EnhancedSignInManager<TUser, TKey> : SignInManager<TUser, TKey>
    where TUser : class, IUser<TKey>
    where TKey : IEquatable<TKey>
{
    public EnhancedSignInManager(
        UserManager<TUser, TKey> userManager, 
        IAuthenticationManager authenticationManager)
        : base(userManager, authenticationManager)
    {
    }

    public override async Task SignInAsync(
        TUser user, 
        bool isPersistent, 
        bool rememberBrowser)
    {
        var userIdentity = await CreateUserIdentityAsync(user).WithCurrentCulture();

        // Clear any partial cookies from external or two factor partial sign ins
        AuthenticationManager.SignOut(
            DefaultAuthenticationTypes.ExternalCookie, 
            DefaultAuthenticationTypes.TwoFactorCookie);

        if (rememberBrowser)
        {
            var rememberBrowserIdentity = AuthenticationManager
                .CreateTwoFactorRememberBrowserIdentity(ConvertIdToString(user.Id));

            AuthenticationManager.SignIn(
                new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity, 
                rememberBrowserIdentity);
        }
        else
        {
            AuthenticationManager.SignIn(
                new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity);
        }
    }

    private async Task<SignInStatus> SignInOrTwoFactor(TUser user, bool isPersistent)
    {
        var id = Convert.ToString(user.Id);

        if (UserManager.SupportsUserTwoFactor 
            && await UserManager.GetTwoFactorEnabledAsync(user.Id)
                                .WithCurrentCulture()
            && (await UserManager.GetValidTwoFactorProvidersAsync(user.Id)
                                 .WithCurrentCulture()).Count > 0
                && !await AuthenticationManager.TwoFactorBrowserRememberedAsync(id)
                                               .WithCurrentCulture())
        {
            var identity = new ClaimsIdentity(
                DefaultAuthenticationTypes.TwoFactorCookie);

            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id));

            AuthenticationManager.SignIn(identity);

            return SignInStatus.RequiresVerification;
        }
        await SignInAsync(user, isPersistent, false).WithCurrentCulture();
        return SignInStatus.Success;
    }

    public override async Task<SignInStatus> PasswordSignInAsync(
        string userName, 
        string password, 
        bool isPersistent, 
        bool shouldLockout)
    {
        if (UserManager == null)
        {
            return SignInStatus.Failure;
        }

        var user = await UserManager.FindByNameAsync(userName).WithCurrentCulture();
        if (user == null)
        {
            return SignInStatus.Failure;
        }

        if (UserManager.SupportsUserLockout 
            && await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
        {
            return SignInStatus.LockedOut;
        }

        if (UserManager.SupportsUserPassword 
            && await UserManager.CheckPasswordAsync(user, password)
                                .WithCurrentCulture())
        {
            return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
        }
        if (shouldLockout && UserManager.SupportsUserLockout)
        {
            // If lockout is requested, increment access failed count
            // which might lock out the user
            await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture();
            if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
            {
                return SignInStatus.LockedOut;
            }
        }
        return SignInStatus.Failure;
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助.干杯

  • 这不是我需要的,但这有助于我指出正确的道路.我必须管理员,我很生气,我不得不花费大量时间让Identity与我现有的数据库一起工作. (5认同)

Emi*_*adh 5

我有同样的问题,我不想实施只是IUserTwoFactorStore<TUser, TKey>说我不实施它。但如果我最终想要实现它(我预计我会的),我也不想回去胡思乱想。所以我认为未来证明(且可重复使用)的解决方案是:(受到@gjsduarte的答案的启发)

public class SafeUserManager<TUser, TKey> : UserManager<TUser, TKey>
{
    public override Task<bool> GetTwoFactorEnabledAsync(TKey userId)
    {
        return Store is IUserTwoFactorStore<TUser, TKey>
            ? base.GetTwoFactorEnabledAsync(userId)
            : Task.FromResult(false);
    }
}
Run Code Online (Sandbox Code Playgroud)

对其他方法做同样的事情可能是个好主意Get[feature]EnabledAsync(TKey userId)