2015-10-05 24 views
6

Sto cercando di trovare un modo per disabilitare un utente in Identity 2.0 e non riesco a trovare alcuna informazione su di esso.Come disabilitare un utente in Identity 2.0?

Vorrei impostare fondamentalmente un utente su IsActive = false e preferirei farlo appena l'utente è stato creato. Tuttavia, ho bisogno di un modo per impostare IsActive per il nostro amministratore del sito. Ho già questo con abbonamento ASP.Net ma sto cercando di nascondere il sito per MVC e Identity.

Per le mie esigenze chiediamo alle persone di andare avanti e registrare un account, ma vogliamo che sia disabilitato di default. Quindi, quando riceviamo il pagamento per l'adesione, torneremo indietro e li abiliteremo. Lo usiamo anche per disabilitare gli utenti quando il loro abbonamento è attivo e non si sono rinnovati.

C'è un modo per disabilitare un account senza eliminarlo o bloccarlo solo per un periodo di tempo X? Finora non ho trovato alcun modo di disabilitare un utente in Identity e sono sorpreso che questa domanda non sia mai emersa prima.

risposta

11

Quando si crea un sito con i bit di identità installate, il sito avrà un file chiamato "IdentityModels.cs". In questo file è una classe denominata ApplicationUser che eredita da IdentityUser.

// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. 
public class ApplicationUser : IdentityUser 

C'è un bel link nei commenti lì, per la facilità cliccare here

Questo tutorial ti dice esattamente che cosa dovete fare per aggiungere proprietà personalizzate per l'utente.

E in realtà, non preoccupatevi nemmeno di guardare il tutorial.

1) aggiungere una proprietà alla classe ApplicationUser, ad esempio:

public bool? IsEnabled { get; set; } 

2) aggiungere una colonna con lo stesso nome sul tavolo AspNetUsers nel vostro DB.

3) boom, il gioco è fatto!

Ora nel tuo AccountController, si hanno un'azione Registrati come segue:

public async Task<ActionResult> Register(RegisterViewModel model) 
     { 
      if (ModelState.IsValid) 
      { 
       var user = new ApplicationUser { UserName = model.Email, Email = model.Email, IsEnabled = true }; 
       var result = await UserManager.CreateAsync(user, model.Password); 
       if (result.Succeeded) 

ho aggiunto l'IsEnabled = true sulla creazione dell'oggetto ApplicationUser. Il valore verrà ora mantenuto nella nuova colonna nella tabella AspNetUsers.

Sarà quindi necessario gestire il controllo di questo valore come parte del processo di accesso, eseguendo l'override di PasswordSignInAsync in ApplicationSignInManager.

ho fatto come segue:

public override Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool rememberMe, bool shouldLockout) 
    { 
     var user = UserManager.FindByEmailAsync(userName).Result; 

     if ((user.IsEnabled.HasValue && !user.IsEnabled.Value) || !user.IsEnabled.HasValue) 
     { 
      return Task.FromResult<SignInStatus>(SignInStatus.LockedOut); 
     } 

     return base.PasswordSignInAsync(userName, password, rememberMe, shouldLockout); 
    } 

tua situazione potrebbe essere diversa, e non si può decidere di tornare che SignInStatus, ma si ottiene l'idea.

+1

Come si ottiene lo stesso risultato in ASP.NET Core 1.0 con Identity 3.0 che non ha ApplicationSignInManager o PasswordSignInAsync (...)? – nam

+0

L'uso di '.Result' è contro le raccomandazioni ed è noto che causa deadlock in alcuni scenari, inoltre blocca il thread che sconfigge l'intero punto di asincronia. Sarebbe preferibile contrassegnare il metodo 'PasswordSignInAsync' come' async' e attendere 'FindByEmailAsync'. – TKharaishvili

+1

Il problema più grande con questo è se sono già registrati, non li riguarderà. In particolare se hanno selezionato la casella di controllo Ricordami. Se accedono regolarmente al sito, non avranno mai bisogno di accedere. Sto cercando di capire se è possibile utilizzare la logica di blocco esistente per questo, e se è meglio gestire gli utenti che hanno già effettuato l'accesso . –

0

Passaggio 1: creare un archivio utente personalizzato che implementa IUserLockoutStore.

 public Task<DateTimeOffset> GetLockoutEndDateAsync(MyUser user) 
    { 
     //.. 
    } 

    public Task SetLockoutEndDateAsync(MyUser user, DateTimeOffset lockoutEnd) 
    { 
     //.. 
    } 

    public Task<int> IncrementAccessFailedCountAsync(MyUser user) 
    { 
     //.. 
    } 

    public Task ResetAccessFailedCountAsync(MyUser user) 
    { 
     //.. 
    } 

    public Task<int> GetAccessFailedCountAsync(MyUser user) 
    { 
     //.. 
    } 

    public Task<bool> GetLockoutEnabledAsync(MyUser user) 
    { 
     //.. 
    } 

    public Task SetLockoutEnabledAsync(MyUser user, bool enabled) 
    { 
     //.. 
    } 
} 

Passo # 2: Invece di UserManager, utilizzare la seguente classe nel vostro login/logout azioni, passandogli un'istanza del tuo negozio utente personalizzato.

public class LockingUserManager<TUser, TKey> : UserManager<TUser, TKey> 
    where TUser : class, IUser<TKey> 
    where TKey : IEquatable<TKey> 
{ 
    private readonly IUserLockoutStore<TUser, TKey> _userLockoutStore; 

    public LockingUserManager(IUserLockoutStore<TUser, TKey> store) 
     : base(store) 
    { 
     if (store == null) throw new ArgumentNullException("store"); 

     _userLockoutStore = store; 
    } 

    public override async Task<TUser> FindAsync(string userName, string password) 
    { 
     var user = await FindByNameAsync(userName); 

     if (user == null) return null; 

     var isUserLockedOut = await GetLockoutEnabled(user); 

     if (isUserLockedOut) return user; 

     var isPasswordValid = await CheckPasswordAsync(user, password); 

     if (isPasswordValid) 
     { 
      await _userLockoutStore.ResetAccessFailedCountAsync(user); 
     } 
     else 
     { 
      await IncrementAccessFailedCount(user); 

      user = null; 
     } 

     return user; 
    } 

    private async Task<bool> GetLockoutEnabled(TUser user) 
    { 
     var isLockoutEnabled = await _userLockoutStore.GetLockoutEnabledAsync(user); 

     if (isLockoutEnabled == false) return false; 

     var shouldRemoveLockout = DateTime.Now >= await _userLockoutStore.GetLockoutEndDateAsync(user); 

     if (shouldRemoveLockout) 
     { 
      await _userLockoutStore.ResetAccessFailedCountAsync(user); 

      await _userLockoutStore.SetLockoutEnabledAsync(user, false); 

      return false; 
     } 

     return true; 
    } 

    private async Task IncrementAccessFailedCount(TUser user) 
    { 
     var accessFailedCount = await _userLockoutStore.IncrementAccessFailedCountAsync(user); 

     var shouldLockoutUser = accessFailedCount > MaxFailedAccessAttemptsBeforeLockout; 

     if (shouldLockoutUser) 
     { 
      await _userLockoutStore.SetLockoutEnabledAsync(user, true); 

      var lockoutEndDate = new DateTimeOffset(DateTime.Now + DefaultAccountLockoutTimeSpan); 

      await _userLockoutStore.SetLockoutEndDateAsync(user, lockoutEndDate); 
     } 
    } 
} 

ESEMPIO

[AllowAnonymous] 
    [HttpPost] 
    public async Task<ActionResult> Login(string userName, string password) 
    { 
     var userManager = new LockingUserManager<MyUser, int>(new MyUserStore()) 
     { 
      DefaultAccountLockoutTimeSpan = /* get from appSettings */, 
      MaxFailedAccessAttemptsBeforeLockout = /* get from appSettings */ 
     }; 

     var user = await userManager.FindAsync(userName, password); 

     if (user == null) 
     { 
      // bad username or password; take appropriate action 
     } 

     if (await _userManager.GetLockoutEnabledAsync(user.Id)) 
     { 
      // user is locked out; take appropriate action 
     } 

     // username and password are good 
     // mark user as authenticated and redirect to post-login landing page 
    } 

Source

+0

Potrei essere confuso su questo o non affronta la domanda. Quello che prendo dal codice sarebbe usato per vedere se l'utente si trova in uno stato di blocco che verrebbe da tentativi di accesso non riusciti. Sembra che imposti solo un tempo di logout e il numero di tentativi di accesso falliti prima di bloccarli. Sto cercando di vedere se posso disabilitare l'account. Fare qualcosa come impostare IsActive = false. In questo modo non riescono ad accedere al periodo. Quando si verifica un rinnovo, resettare semplicemente IsActive = true. Qualcosa di simile a quello. Guarderò ancora il codice e vedrò se funzionerà. – Caverman

+0

Volevo lanciare un'idea che tenterò di implementare per disabilitare un utente. Creerò un ruolo chiamato qualcosa come "NoAccess". Quindi sui miei controller non includerò quel ruolo come uno che può arrivare a qualsiasi ActionResult. Nel mio caso lo userò come ruolo predefinito quando qualcuno si iscrive. Penso che si prenderà cura dei miei bisogni. – Caverman

+0

Tuttavia, sembra che potrei non dover impostare Identity per bloccare dopo alcuni accessi non riusciti o utilizzare il codice sopra. Sono sorpreso che Microsoft non abbia reso più facile guardare qualcuno che è stato bloccato e/o un modo più semplice per sbloccarli. – Caverman

3

Stava facendo qualche ricerca su questo e risulta che la classe base IdentityUser abbia alcune proprietà correlate a questo argomento. Vale a dire: LockoutEnabled e LockoutEndDateUtc.

E 'sufficiente impostare LockoutEnabled a true e LockoutEndDateUtc ad una data futura al fine per lo standard SignInManager.PasswordSignInAsync per raccoglierlo e agire di conseguenza, senza sostituzioni o personalizzazioni.

E se si desidera semplicemente disabilitare l'utente senza specificare alcuna data esatta di riattivazione, è sufficiente impostarlo su DateTime.MaxValue.

Problemi correlati