2014-08-28 2 views
17

Я создал обычай IUserStore<TUser,int> для моего приложения. Я реализовал интерфейсы мне нужно,Пользовательский ASP.NET Identity 2.0 UserStore - Выполняет ли все необходимые интерфейсы?

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

, но когда я называю

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

я получаю исключение, говоря

Store does not implement IUserTwoFactorStore<TUser>. 

Я не использую проверку подлинности два фактора в любом месте в моем заявление. Почему он ожидает, что я реализую этот интерфейс? Требуется ли реализовать все эти интерфейсы, даже если я их фактически не использую?

ответ

14

У меня была та же проблема. На данный момент, поскольку метод SignInManager.SignInOrTwoFactor слепо проверяет GetTwoFactorAuthentication, он генерирует исключение, когда UserStore не реализует IUserTwoFactorStore.

Я считаю, что Microsoft предполагала, что метод SignInManager PasswordSignInAsync должен быть переопределен в пользовательском классе SignInManager. К сожалению, я не мог найти документацию или образцы, указывающие на это.

Вот обертка класс 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; 
    } 
} 

Я надеюсь, что это помогает. Приветствия

+0

Спасибо, помог мне преодолеть нынешний барьер. – Andez

+4

Это не совсем то, что мне нужно, но это помогло мне указать на правильный путь. Я должен администратор, я так раздражен, что мне нужно потратить кучу часов, чтобы заставить Identity работать с моей существующей базой данных. –

+1

Я получаю эту ошибку: «System.Threading.Tasks.Task» не содержит определения для «WithCurrentCulture». Я что-то пропустил? Кажется, что правильные слова. – fcaldera

15

На самом деле интерфейс IUserTwoFactorStore действительно просто, до сих пор моя реализация (я не использую два фактора аутентификации либо) заключается в следующем:

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

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

Он работает, хотя я только что сделал это пару минут назад не тестировал все приложение полностью.

+9

Да, это сработает, но это довольно неприятно. Он убивает принцип подписи Лискова. Я думаю, можно с уверенностью сказать, что не проверка реализации IUserTwoFactorStore - это ошибка дизайна в классе Identity Identity. –

1

У меня была такая же проблема, и я не хочу реализовывать 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); 
    } 
} 

Это, вероятно, будет хорошей идеей, чтобы сделать то же самое для других Get[feature]EnabledAsync(TKey userId) методов.

Смежные вопросы