2014-08-28 3 views
17

Ho creato una personalizzata IUserStore<TUser,int> per la mia applicazione. Ho implementato le interfacce di cui ho bisogno,Custom User ID di ASP.NET 2.0 - L'implementazione di tutte le interfacce è necessaria?

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

ma quando chiamo

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

ottengo un'eccezione dicendo

Store does not implement IUserTwoFactorStore<TUser>. 

non sto usando l'autenticazione a due fattori in qualsiasi parte mia applicazione. Perché si aspetta che io implementi quell'interfaccia? È necessario che io implementi tutte queste interfacce, anche se in realtà non le uso?

risposta

14

Ho avuto lo stesso problema. Per il momento, poiché il metodo SignInManager.SignInOrTwoFactor verifica ciecamente l'autenticazione GetTwoFactorAuthentication, genera un'eccezione quando UserStore non implementa IUserTwoFactorStore.

Credo che Microsoft abbia inteso che il metodo SignInManager PasswordSignInAsync deve essere sostituito in una classe SignInManager personalizzata. Sfortunatamente non sono riuscito a trovare documentazione o campioni che lo indicassero.

Ecco la classe wrapper SignInManager ho implementato per risolvere questo problema:

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

spero che aiuta. Acclamazioni

+0

Grazie, mi ha aiutato a superare l'ostacolo attuale. – Andez

+4

Questo non è esattamente quello di cui ho bisogno, ma questo mi ha aiutato a orientarmi nella giusta direzione. Devo amministrare, sono così seccato che devo passare un mucchio di ore per far funzionare Identity con il mio database esistente. –

+1

Viene visualizzato questo errore: 'System.Threading.Tasks.Task' non contiene una definizione per 'WithCurrentCulture'. Ho dimenticato qualcosa? Sembra che gli usi siano corretti. – fcaldera

15

In realtà l'interfaccia IUserTwoFactorStore è molto semplice, finora la mia applicazione (Non faccio uso di due fattore di autenticazione sia) è questo:

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

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

Funziona, anche se ho fatto solo paio di minuti fa e non ha testato completamente l'intera app.

+9

Sì, funzionerà, ma è piuttosto brutto. Uccide il principio di sostituzione di liskov. Penso che sia sicuro dire che il non controllo di un'implementazione di IUserTwoFactorStore è un difetto di progettazione nella classe Manager di Identity. –

1

Ho avuto lo stesso problema e non voglio implementare lo IUserTwoFactorStore<TUser, TKey> solo per dire che non lo implemento. Ma anche io non voglio tornare indietro e muck in giro se finisco per volere implementarlo (che anticiperò lo farò). Quindi quello che considero un a prova di futuro (e riutilizzabile) soluzione potrebbe essere: (ispirati @ di gjsduarte risposta)

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

Probabilmente sarebbe una buona idea di fare lo stesso per gli altri Get[feature]EnabledAsync(TKey userId) metodi.