2015-10-05 4 views
6

Ich versuche eine Möglichkeit zu finden, einen Benutzer in Identity 2.0 zu deaktivieren und scheint keine Informationen darüber zu finden.So deaktivieren Sie einen Benutzer in Identity 2.0?

Ich möchte im Grunde einen Benutzer zu IsActive = false setzen und würde es tun, sobald der Benutzer erstellt wird. Ich benötige jedoch einen Weg, um den IsActive für unseren Site-Administrator festzulegen. Ich habe dies bereits mit ASP.Net-Mitgliedschaft, aber ich möchte die Website zu MVC und Identität zu verdecken.

Für meine Anforderungen bitten wir Leute, weiterzumachen und ein Konto zu registrieren, aber wir wollen, dass es standardmäßig deaktiviert ist. Wenn wir die Zahlung für den Beitritt erhalten, werden wir zurückgehen und sie aktivieren. Wir verwenden es auch, um Benutzer zu deaktivieren, wenn ihr Abonnement läuft und sie nicht erneuert wurden.

Gibt es eine Möglichkeit, ein Konto zu deaktivieren, ohne es zu löschen oder nur für eine X Zeit zu sperren? Bislang habe ich noch keine Möglichkeit gefunden, einen Benutzer in Identity zu deaktivieren und ich bin überrascht, dass diese Frage noch nicht aufgetaucht ist.

Antwort

11

Wenn Sie eine Website mit der Identität Bits installiert erstellen, Ihre Website wird eine Datei "IdentityModels.cs" genannt haben. In dieser Datei befindet sich eine Klasse namens ApplicationUser, die von IdentityUser erbt.

// 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 

Es gibt einen schönen Link in den Kommentaren gibt, für eine einfache klicken here

Dieses Tutorial zeigt Ihnen genau, was Sie benutzerdefinierte Eigenschaften für Ihre Benutzer tun müssen hinzuzufügen.

Und tatsächlich, nicht einmal die Mühe, das Tutorial zu betrachten.

1) eine Eigenschaft der ApplicationUser Klasse hinzufügen, zum Beispiel:

public bool? IsEnabled { get; set; } 

2) eine Spalte mit dem gleichen Namen auf dem in Ihrer DB AspNetUsers Tisch.

3) Boom, das war's!

Jetzt in Ihrem Account, haben Sie eine Aktion Register wie folgt:

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) 

ich die IsEnabled = true auf die Schaffung des ApplicationUser Objekt hinzugefügt haben. Der Wert wird jetzt in Ihrer neuen Spalte in der AspNetUsers-Tabelle beibehalten.

Sie müssten sich dann mit der Überprüfung dieses Werts als Teil der Anmeldung befassen, indem Sie PasswordSignInAsync in ApplicationSignInManager überschreiben.

Ich habe es wie folgt:

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

Leistung kann variieren, und Sie können nicht, dass SignInStatus zurückkehren wollen, aber Sie bekommen die Idee.

+1

Wie erreichen Sie das gleiche in ASP.NET Core 1.0 mit Identity 3.0, das nicht ApplicationSignInManager oder PasswordSignInAsync (...) hat? – nam

+0

Die Verwendung von '.Result' ist gegen Empfehlungen und es ist bekannt, dass es in bestimmten Szenarien Deadlocks verursacht, es blockiert auch den Thread, der den ganzen Punkt der Asynchronität besiegt. Es wäre besser, die 'PasswordSignInAsync'-Methode als' async' zu markieren und stattdessen 'FindByEmailAsync' zu erwarten. – TKharaishvili

+1

Das größte Problem dabei ist, wenn sie bereits angemeldet sind, wird es sie nicht beeinflussen. Vor allem, wenn sie das Anmerkungsfeld aktiviert haben. Wenn sie regelmäßig auf die Site zugreifen, müssen sie sich nie anmelden. Ich versuche herauszufinden, ob die vorhandene Lockout-Logik dafür verwendet werden kann und ob es besser ist, Benutzer zu behandeln, die bereits angemeldet sind . –

0

Schritt 1: Erstellen Sie einen benutzerdefinierten Benutzerspeicher, der IUserLockoutStore implementiert.

 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) 
    { 
     //.. 
    } 
} 

Schritt # 2: Anstelle von Usermanager, verwenden Sie die folgende Klasse in Ihre Login/Logout Aktionen, es ist eine Instanz des benutzerdefinierten Benutzerspeicher übergeben.

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

Beispiel

[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

Ich könnte darüber verwirrt sein oder es befasst sich nicht mit der Frage. Was ich aus dem Code entnehme, würde verwendet werden, um zu sehen, ob sich der Benutzer in einem gesperrten Zustand befindet, der von nicht erfolgreichen Anmeldeversuchen herrühren würde. Es sieht so aus, als ob es nur eine Abmeldezeit und die Anzahl fehlgeschlagener Anmeldeversuche vor dem Sperren setzt. Ich suche, ob ich den Account einfach deaktivieren kann. Etwas wie das Setzen von IsActive = false tun. Auf diese Weise können sie sich einfach nicht einloggen. Wenn eine Erneuerung stattfindet, würde ich nur IsActive = true zurücksetzen. Etwas Ähnliches. Ich werde immer noch über den Code schauen und sehen, ob es funktioniert. – Caverman

+0

Ich wollte eine Idee auswerfen, die ich zum Deaktivieren eines Benutzers implementieren möchte. Ich werde eine Rolle namens "NoAccess" erstellen. Dann werde ich auf meinen Controllern diese Rolle nicht als eine, die zu irgendeinem ActionResult gelangen kann, einschließen. In meinem Fall werde ich das als meine Standardrolle verwenden, wenn sich jemand anmeldet. Ich denke, das wird sich um meine Bedürfnisse kümmern. – Caverman

+0

Es sieht jedoch so aus, als ob ich Identity entweder nach bestimmten fehlgeschlagenen Logins nicht auf Sperren setzen oder den obigen Code verwenden muss. Ich bin überrascht, dass Microsoft es nicht einfacher gemacht hat, jemanden auszusperren und/oder einen einfacheren Weg, sie freizuschalten. – Caverman

3

Wurde eine Untersuchung zu diesem Thema und stellt fest, IdentityUser Basisklasse hat einige Eigenschaften zu diesem Thema. Nämlich: LockoutEnabled und LockoutEndDateUtc.

Es ist ausreichend für die Standard-SignInManager.PasswordSignInAsyncLockoutEnabled zu true und LockoutEndDateUtc zu einem späteren Zeitpunkt zu setzen, um es aufzuheben und ohne Überschreibungen oder Anpassungen entsprechend zu handeln.

Und wenn Sie nur den Benutzer deaktivieren möchten, ohne ein genaues Datum der Reaktivierung anzugeben, können Sie es einfach auf DateTime.MaxValue setzen.