Sur mesure ASP.NET identité 2.0 UserStore - la mise en œuvre de toutes les interfaces est-elle nécessaire?

j'ai créé une coutume IUserStore<TUser,int> pour mon application. J'ai implémenté les interfaces dont j'ai besoin,

   IUserStore<TUser, int>,
   IUserRoleStore<TUser, int>,
   IUserLockoutStore<TUser, int>,
   IUserPasswordStore<TUser, int>

mais quand je l'appelle

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

j'obtiens une exception en disant:

Store does not implement IUserTwoFactorStore<TUser>.

Je n'utilise pas d'authentification à deux facteurs dans mon application. Pourquoi s'attend-il à ce que je mette en œuvre cette interface? Est-il nécessaire que j'implémente toutes ces interfaces, même si Je ne les utilise pas?

17
demandé sur Stephen Collins 2014-08-28 18:26:40

3 réponses

en Fait, le IUserTwoFactorStore interface est vraiment simple, jusqu'à présent, mon application (je n'utilise pas deux facteurs d'authentification) est ceci:

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

 public Task SetTwoFactorEnabledAsync(User user, bool enabled)
 {
     throw new NotImplementedException();
 }

il fonctionne, bien que je l'ai juste fait il ya quelques minutes et n'a pas testé toute l'application à fond.

16
répondu Ignas Vyšnia 2014-12-02 15:40:20

j'ai eu le même problème. Pour le moment, en tant que Gestionnaire des signatures.SignInOrTwoFactor vérifie aveuglément la méthode Getttwofactorauthentication il y a une exception quand L'UserStore n'implémente pas la IUserTwoFactorStore.

je crois que Microsoft a prévu que la méthode Passwordsigninasync de SignInManager doit être remplacée dans une classe custom SignInManager. Malheureusement je n'ai pas pu trouver de documentation ou des échantillons pointant ainsi.

voici le SignInManager classe wrapper j'ai mis en œuvre pour résoudre ce problème:

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;
    }
}

j'espère que cela aide. Acclamations

14
répondu Guilherme Duarte 2014-12-16 15:18:10

j'ai eu le même problème et je ne veux pas mettre en œuvre l' IUserTwoFactorStore<TUser, TKey> juste pour dire que je ne l'implémente pas. Mais je ne veux pas non plus retourner en arrière et de se moquer si je finis par vouloir mettre en œuvre (que je prévois que je vais). Donc ce que je considère comme une future solution de preuve (et réutilisable) serait: (inspiré par la réponse de @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);
    }
}

Il serait probablement une bonne idée de faire la même chose pour les autres Get[feature]EnabledAsync(TKey userId) méthodes.

2
répondu Emil Badh 2017-06-02 01:21:33