Je cherche un moyen de désactiver l’utilisateur plutôt que de le supprimer du système, c’est pour préserver l’intégrité des données. Mais il semble que l'identité ASPNET ne propose que Supprimer le compte.
Il existe une nouvelle fonctionnalité de verrouillage, mais il semble que le verrouillage puisse être contrôlé pour désactiver l'utilisateur, mais ne le verrouille qu'après un certain nombre de tentatives de mot de passe incorrect.
Toutes les autres options?
Lorsque vous créez un site avec les bits d'identité installés, votre site contiendra un fichier appelé "IdentityModels.cs". Dans ce fichier, une classe appelée ApplicationUser hérite d'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
Il y a un joli lien dans les commentaires ici, pour plus de facilité cliquez ici
Ce tutoriel vous explique exactement ce que vous devez faire pour ajouter des propriétés personnalisées à votre utilisateur.
Et en fait, ne même pas la peine de regarder le tutoriel.
1) ajoutez une propriété à la classe ApplicationUser, par exemple:
public bool? IsEnabled { get; set; }
2) ajoutez une colonne du même nom dans la table AspNetUsers de votre base de données.
3) boum, c'est tout!
Maintenant, dans votre AccountController, vous avez une action d’enregistrement comme suit:
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)
J'ai ajouté IsEnabled = true à la création de l'objet ApplicationUser. La valeur sera maintenant conservée dans votre nouvelle colonne dans la table AspNetUsers.
Vous devrez ensuite vérifier la valeur de cette valeur dans le cadre du processus de connexion en remplaçant PasswordSignInAsync dans ApplicationSignInManager.
Je l'ai fait comme suit:
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);
}
Votre kilométrage peut varier et vous ne voudrez peut-être pas retourner ce SignInStatus, mais vous avez l’idée.
Vous n'avez pas besoin de créer une propriété personnalisée. L'astuce consiste à définir la propriété LockoutEnabled
sur l'utilisateur d'identité ET la valeur LockoutoutEndDateUtc
à une date ultérieure de votre code pour verrouiller un utilisateur. Ensuite, appeler le UserManager.IsLockedOutAsync(user.Id
) renverra false.
LockoutEnabled
et LockoutoutEndDateUtc
doivent répondre aux critères de date vraie et future pour pouvoir verrouiller un utilisateur. Si, par exemple, la valeur LockoutoutEndDateUt
c est 2014-01-01 00:00:00.000
et que LockoutEnabled
est true
, l'appel de la UserManager.IsLockedOutAsync(user.Id)
renverra toujours true
. Je peux comprendre pourquoi Microsoft l’a conçu de cette manière, de sorte que vous puissiez définir une période de temps pendant laquelle un utilisateur est verrouillé.
Cependant, je dirais que cela devrait être le cas si LockoutEnabled
est true
, alors l'utilisateur devrait être verrouillé si LockoutoutEndDateUtc
est NULL OR une date ultérieure. Ainsi, votre code ne vous préoccupera pas de la définition de deux propriétés (LockoutoutEndDateUtc
est NULL
par défaut). Vous pouvez simplement définir LockoutEnabled
sur true
et si LockoutoutEndDateUtc
est NULL
, l'utilisateur est verrouillé indéfiniment.
La propriété par défaut LockoutEnabled
pour une User
n'est pas la propriété indiquant si un utilisateur est actuellement verrouillé ou non. C'est une propriété indiquant si l'utilisateur doit être soumis au verrouillage ou non une fois que la variable AccessFailedCount
atteint la valeur MaxFailedAccessAttemptsBeforeLockout
. Même si l'utilisateur est verrouillé, il ne s'agit que d'une mesure temporaire pour l'interdire pour la durée de la propriété LockedoutEnddateUtc
. Par conséquent, pour désactiver ou suspendre de manière permanente un compte d'utilisateur, vous pouvez introduire votre propre propriété d'indicateur.
Vous devez introduire votre propre indicateur dans une classe dérivée IdentityUser personnalisée et implémenter/appliquer votre propre logique d'activation/désactivation et empêcher l'utilisateur de se connecter s'il est désactivé.
Vous pouvez utiliser ces classes ... Une implémentation propre de l'identité ASP.NET ... C'est mon propre code. int est ici pour la clé primaire si vous voulez un type différent pour la clé primaire, vous pouvez le changer.
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>();
}
}
C'est tout ce que j'ai fait en réalité:
var lockoutEndDate = new DateTime(2999,01,01);
UserManager.SetLockoutEnabled(userId,true);
UserManager.SetLockoutEndDate(userId, lockoutEndDate);
C'est essentiellement pour activer le verrouillage (si vous ne le faites pas déjà par défaut, puis définissez la date de fin du verrouillage sur une valeur distante.
Ozz est correct, mais il peut être conseillé de regarder la classe de base et de voir si vous pouvez trouver une méthode vérifiée pour tous les angles de connexion - je pense que cela pourrait être CanSignIn?
Maintenant que MS est open source, vous pouvez voir leur implémentation:
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;
}
}