webentwicklung-frage-antwort-db.com.de

Deaktivieren Sie Benutzer in ASPNET-Identität 2.0

Ich suche nach einer Möglichkeit, den Benutzer zu deaktivieren, anstatt sie aus dem System zu löschen. Dies ist, um die Datenintegrität der zugehörigen Daten zu erhalten. Scheinbar bietet die ASPNET-Identität jedoch nur die Option "Konto löschen". 

Es gibt eine neue Sperrfunktion, aber es scheint, dass die Sperrung gesteuert werden kann, um den Benutzer zu deaktivieren. Der Benutzer kann jedoch nur nach einer bestimmten Anzahl falscher Kennwortversuche gesperrt werden. 

Irgendwelche anderen Möglichkeiten? 

29
anIBMer

Wenn Sie eine Site mit den installierten Identitätsbits erstellen, verfügt Ihre Site über eine Datei mit dem Namen "IdentityModels.cs". In dieser Datei befindet sich eine Klasse mit dem Namen 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 dort. Klicken Sie einfach auf hier

In diesem Lernprogramm erfahren Sie genau, was Sie tun müssen, um benutzerdefinierte Eigenschaften für Ihren Benutzer hinzuzufügen.

Und schauen Sie sich das Tutorial gar nicht erst an.

1) Fügen Sie der ApplicationUser-Klasse eine Eigenschaft hinzu, z.

public bool? IsEnabled { get; set; }

2) Fügen Sie in der AspNetUsers-Tabelle in Ihrer Datenbank eine Spalte mit demselben Namen hinzu.

3) boom, das ist es! 

Jetzt haben Sie in Ihrem AccountController eine Registrierungsaktion 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 habe bei der Erstellung des ApplicationUser-Objekts IsEnabled = true hinzugefügt. Der Wert wird nun in Ihrer neuen Spalte in der AspNetUsers-Tabelle beibehalten.

Sie müssen dann im Rahmen des Anmeldeprozesses nach diesem Wert suchen, indem Sie PasswordSignInAsync in ApplicationSignInManager überschreiben.

Ich habe es wie folgt gemacht:

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

Ihre Laufleistung kann variieren und Sie möchten den SignInStatus möglicherweise nicht zurückgeben, aber Sie haben die Idee.

48
ozz

Sie müssen keine benutzerdefinierte Eigenschaft erstellen. Der Trick besteht darin, die LockoutEnabled-Eigenschaft für den Identitätsbenutzer festzulegen UND die LockoutoutEndDateUtc auf ein zukünftiges Datum aus Ihrem Code zu setzen, um einen Benutzer zu sperren. Beim Aufruf von UserManager.IsLockedOutAsync(user.Id) wird dann false zurückgegeben. 

Sowohl LockoutEnabled als auch LockoutoutEndDateUtc müssen die Kriterien "wahres" und "zukünftiges Datum" erfüllen, um einen Benutzer zu sperren. Wenn der Wert für LockoutoutEndDateUtc beispielsweise 2014-01-01 00:00:00.000 ist und LockoutEnabledtrue ist, wird beim Aufruf vonUserManager.IsLockedOutAsync(user.Id) noch true zurückgegeben. Ich kann sehen, warum Microsoft es so entworfen hat, damit Sie eine Zeitspanne festlegen können, wie lange ein Benutzer gesperrt ist. 

Ich würde jedoch argumentieren, dass es sein sollte, wenn LockoutEnabledtrue ist, und der Benutzer sollte gesperrt werden, wenn LockoutoutEndDateUtc NULL OR eines zukünftigen Datums ist. Auf diese Weise müssen Sie sich in Ihrem Code keine Gedanken über die Einstellung von zwei Eigenschaften machen (LockoutoutEndDateUtc ist standardmäßig NULL). Sie können einfach LockoutEnabled auf true setzen, und wenn LockoutoutEndDateUtcNULL ist, ist der Benutzer auf unbestimmte Zeit gesperrt. 

20

Die standardmäßige LockoutEnabled-Eigenschaft für ein User ist nicht die Eigenschaft, die angibt, ob ein Benutzer derzeit gesperrt ist oder nicht. Diese Eigenschaft gibt an, ob der Benutzer gesperrt werden soll oder nicht, sobald AccessFailedCount den MaxFailedAccessAttemptsBeforeLockout-Wert erreicht. Selbst wenn der Benutzer gesperrt ist, ist dies nur eine vorübergehende Maßnahme, um den Benutzer für die Dauer der LockedoutEnddateUtc-Eigenschaft zu sperren. Um ein Benutzerkonto dauerhaft zu deaktivieren oder zu sperren, möchten Sie möglicherweise Ihre eigene Flag-Eigenschaft einfügen. 

15
user2813261

Sie müssen Ihr eigenes Flag in eine benutzerdefinierte, von IdentityUser abgeleitete Klasse einführen und Ihre eigene Logik bezüglich Aktivieren/Deaktivieren implementieren/durchsetzen und verhindern, dass sich der Benutzer bei Deaktivierung anmeldet.

9
Brock Allen

Sie können diese Klassen verwenden ... Eine saubere Implementierung von ASP.NET-Identität ..... Es ist mein eigener Code. int ist hier für Primärschlüssel, wenn Sie einen anderen Typ für Primärschlüssel wünschen, den Sie ändern können.

IdentityConfig.cs

public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
    public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
        : base(store)
    {
    }
    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get<ApplicationContext>()));
        manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        manager.UserLockoutEnabledByDefault = false;
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<ApplicationUser, int>(
                    dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}
public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
    public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) :
        base(userManager, authenticationManager) { }
    public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
        return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    }
    public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
    {
        return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
    }
}
public class ApplicationRoleManager : RoleManager<ApplicationRole, int>
{
    public ApplicationRoleManager(IRoleStore<ApplicationRole, int> store)
        : base(store)
    {
    }
}
public class ApplicationRoleStore : RoleStore<ApplicationRole, int, ApplicationUserRole>
{
    public ApplicationRoleStore(ApplicationContext db)
        : base(db)
    {
    }
}
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, int,
ApplicationLogin, ApplicationUserRole, ApplicationClaim>
{
    public ApplicationUserStore(ApplicationContext db)
        : base(db)
    {
    }
}

IdentityModel.cs

public class ApplicationUser : IdentityUser<int, ApplicationLogin, ApplicationUserRole, ApplicationClaim>
{   
    //your property 
    //flag for users state (active, deactive or enabled, disabled)
    //set it false to disable users
    public bool IsActive { get; set; }
    public ApplicationUser()
    {
    }
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}
public class ApplicationUserRole : IdentityUserRole<int>
{
}
public class ApplicationLogin : IdentityUserLogin<int>
{
    public virtual ApplicationUser User { get; set; }
}
public class ApplicationClaim : IdentityUserClaim<int>
{
    public virtual ApplicationUser User { get; set; }
}
public class ApplicationRole : IdentityRole<int, ApplicationUserRole>
{
    public ApplicationRole()
    {
    }
}
public class ApplicationContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationLogin, ApplicationUserRole, ApplicationClaim>
{
    //web config connectionStringName DefaultConnection change it if required
    public ApplicationContext()
        : base("DefaultConnection")
    {
        Database.SetInitializer<ApplicationContext>(new CreateDatabaseIfNotExists<ApplicationContext>());
    }
    public static ApplicationContext Create()
    {
        return new ApplicationContext();
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    }
}  

Für Beispielcode

3
Deniz Kısır

Das alles, was ich tatsächlich gemacht habe: 

    var lockoutEndDate = new DateTime(2999,01,01);
    UserManager.SetLockoutEnabled(userId,true);
    UserManager.SetLockoutEndDate(userId, lockoutEndDate);

Dies ist im Wesentlichen das Aktivieren der Sperrung (wenn Sie dies nicht bereits standardmäßig tun und dann das Enddatum der Sperrung auf einen entfernten Wert setzen).

1
t_plusplus

Ich habe Watson auf den neuesten Stand gebracht, da es in SignInManager eine andere öffentliche Methode gibt, die TUser-Benutzer anstelle der Zeichenfolge userName akzeptiert. Die akzeptierte Antwort schlägt nur vor, die Methode mit der Signatur des Benutzernamens zu überschreiben. Beides sollte wirklich außer Kraft gesetzt werden, da es sonst eine Möglichkeit gibt, einen behinderten Benutzer anzumelden. Hier sind die beiden Methoden in der Basisimplementierung:

public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)
{
  var user = await UserManager.FindByNameAsync(userName);
  if (user == null)
  {
    return SignInResult.Failed;
  }

  return await PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
}

public virtual async Task<SignInResult> PasswordSignInAsync(User user, string password, bool isPersistent, bool lockoutOnFailure)
{
  if (user == null)
  {
    throw new ArgumentNullException(nameof(user));
  }

  var attempt = await CheckPasswordSignInAsync(user, password, lockoutOnFailure);
  return attempt.Succeeded
      ? await SignInOrTwoFactorAsync(user, isPersistent)
      : attempt;
}

Das Überschreiben von CanSignIn scheint mir eine bessere Lösung zu sein, da es von PreSignInCheck aufgerufen wird, das in CheckPasswordSignInAsync aufgerufen wird. Nach dem, was ich aus der Quelle ersehen kann, sollte das Überschreiben von CanSignIn alle Szenarien abdecken. Hier ist eine einfache Implementierung, die verwendet werden könnte:

public override async Task<bool> CanSignInAsync(User user)
{
  var canSignIn = user.IsEnabled;

  if (canSignIn) { 
    canSignIn = await base.CanSignInAsync(user);
  }
  return canSignIn;
}
0
DanO

Ozz ist korrekt, es kann jedoch ratsam sein, sich die Basisklasse anzusehen und herauszufinden, ob Sie eine Methode finden können, die für alle Vorzeichenwinkel geprüft wird. Ich denke, es könnte CanSignIn sein.

Nun, da MS Open Source ist, können Sie deren Implementierung sehen: 

https://github.com/aspnet/AspNetCore/blob/master/src/Identity/src/Identity/SignInManager.cs

    public class CustomSignInManager : SignInManager<ApplicationUser>  
{
    public CustomSignInManager(UserManager<ApplicationUser> userManager,
        IHttpContextAccessor contextAccessor,
        IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory,
        IOptions<IdentityOptions> optionsAccessor,
        ILogger<SignInManager<ApplicationUser>> logger,
        IAuthenticationSchemeProvider schemes) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
    {

    }


    public override async Task<bool> CanSignInAsync(ApplicationUser user)
    {
        if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user)))
        {
            Logger.LogWarning(0, "User {userId} cannot sign in without a confirmed email.", await UserManager.GetUserIdAsync(user));
            return false;
        }
        if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user)))
        {
            Logger.LogWarning(1, "User {userId} cannot sign in without a confirmed phone number.", await UserManager.GetUserIdAsync(user));
            return false;
        }

        if (UserManager.FindByIdAsync(user.Id).Result.IsEnabled == false)
        {
            Logger.LogWarning(1, "User {userId} cannot sign because it's currently disabled", await UserManager.GetUserIdAsync(user));
            return false;
        }

        return true;
    }
}
0
Watson

Sie müssen Ihr eigenes UserStore implementieren, um die Identität zu entfernen.

Auch das könnte dir helfen.