web-dev-qa-db-fra.com

ASP.NET MVC 5 comment supprimer un utilisateur et ses données associées dans Identity 2.0

Bonjour, je suis cet article pour supprimer un utilisateur dans Identity 2.0 http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-details-and-delete-methods

Cependant, je dois d'abord supprimer tous les enregistrements associés dans AspNetUserRoles, puis supprimer l'utilisateur.

J'ai trouvé un exemple écrit dans Identity 1.0 et certaines des méthodes utilisées dans cet exemple n'existent pas.

   // POST: /Users/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> DeleteConfirmed(string id)
        {
            if (ModelState.IsValid)
            {
                if (id == null)
                {
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }

                var user = await context.Users.FindAsync(id);
                var logins = user.Logins;
                foreach (var login in logins)
                {
                    context.UserLogins.Remove(login);
                }
                var rolesForUser = await IdentityManager.Roles.GetRolesForUserAsync(id, CancellationToken.None);
                if (rolesForUser.Count() > 0)
                {

                    foreach (var item in rolesForUser)
                    {
                        var result = await IdentityManager.Roles.RemoveUserFromRoleAsync(user.Id, item.Id, CancellationToken.None);
                    }
                }
                context.Users.Remove(user);
                await context.SaveChangesAsync();
                return RedirectToAction("Index");
            }
            else
            {
                return View();
            }
        }

Je ne peux pas trouver IdentityManager de n'importe où et context.Users n'a pas non plus de méthode FindAsync().

Aidez-nous à comprendre comment supprimer correctement un utilisateur et ses enregistrements associés dans Identity 2.0.

Merci.

29
Franva

Je pense que les classes que vous recherchez sont le UserManager et le RoleManager . À mon avis, ils constituent la meilleure solution au lieu d’agir directement contre le contexte.

UserManager définit une méthode RemoveFromRoleAsync qui vous permet de supprimer l'utilisateur (identifié par sa clé) d'un rôle donné. Il définit également plusieurs méthodes de recherche, telles que FindAsync , FindByIdAsync , FindByNameAsync ou FindByEmailAsync . Ils peuvent tous être utilisés pour récupérer un utilisateur. Pour supprimer un utilisateur, vous devez utiliser la méthode DeleteAsync qui accepte un objet utilisateur en tant que paramètre. Pour obtenir les rôles qu'un utilisateur est membre d'Identity, vous devez utiliser la méthode GetRolesAsync dans laquelle vous transmettez l'ID de l'utilisateur. De plus, je vois que vous essayez de supprimer une connexion d'un utilisateur. Pour cela, vous devez utiliser la méthode RemoveLoginAsync .

Dans l’ensemble, votre code ressemblerait au suivant:

// POST: /Users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(string id)
{
  if (ModelState.IsValid)
  {
    if (id == null)
    {
      return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    var user = await _userManager.FindByIdAsync(id);
    var logins = user.Logins;
    var rolesForUser = await _userManager.GetRolesAsync(id);

    using (var transaction = context.Database.BeginTransaction())
    {
      foreach (var login in logins.ToList())
      {
        await _userManager.RemoveLoginAsync(login.UserId, new UserLoginInfo(login.LoginProvider, login.ProviderKey));
      }

      if (rolesForUser.Count() > 0)
      {
        foreach (var item in rolesForUser.ToList())
        {
          // item should be the name of the role
          var result = await _userManager.RemoveFromRoleAsync(user.Id, item);
        }
      }

      await _userManager.DeleteAsync(user);
      transaction.Commit();
    }

    return RedirectToAction("Index");
  }
  else
  {
    return View();
  }
}

Vous devrez adapter cet extrait à vos besoins, car je ne sais pas comment votre implémentation IdentityUser ressemblera. N'oubliez pas de déclarer le UserManager au besoin. Vous trouverez un exemple de la procédure à suivre lorsque vous créez un nouveau projet dans Visual Studio à l'aide de Comptes individuels.

55
Horizon_Net

Mise à jour pour ASP.NET Core 2.0 - espérons que cela fera gagner un peu de temps à quelqu'un

ApplicationDbContext context, 
UserManager<ApplicationUser> userManager, 
ApplicationUser user

var logins = await userManager.GetLoginsAsync(user);
var rolesForUser = await userManager.GetRolesAsync(user);

using (var transaction = context.Database.BeginTransaction())
{
    IdentityResult result = IdentityResult.Success;
    foreach (var login in logins)
    {
        result = await userManager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey);
        if (result != IdentityResult.Success)
            break;
    }
    if (result == IdentityResult.Success)
    {
        foreach (var item in rolesForUser)
        {
            result = await userManager.RemoveFromRoleAsync(user, item);
            if (result != IdentityResult.Success)
                break;
        }
    }
    if (result == IdentityResult.Success)
    {
        result = await userManager.DeleteAsync(user);
        if (result == IdentityResult.Success)
            transaction.Commit(); //only commit if user and all his logins/roles have been deleted  
    }
}
2
wpqs
  • L'argument de Brad à propos de l'obligation de @ Html.AntiForgeryToken () dans les vues n'est pas nécessaire si vous utilisez les dernières versions d'ASP.NET - voir AntiForgeryToken toujours requis
  • Pourquoi ne pas créer un déclencheur SQL pour AspNetUsers afin de supprimer un utilisateur supprime également les enregistrements correspondants pour l'utilisateur de AspNetUserRoles et AspNetUserLogins?
  • J'ai besoin d'appeler DeleteUser depuis un certain nombre d'endroits. J'ai donc ajouté une méthode statique à AccountController (voir ci-dessous). J'apprends toujours sur MVC, je devrais donc être reconnaissant pour les commentaires, en particulier 1) l'utilisation d'IdentityResult en tant que code de retour 2) l'opportunité d'étendre AccountController de cette manière 3) l'approche permettant d'insérer un mot de passe (texte en clair) dans le modèle afin de valider le code. action (voir exemple d'invocation). 

     public static async Task<IdentityResult> DeleteUserAccount(UserManager<ApplicationUser> userManager, 
                                                                             string userEmail, ApplicationDbContext context)
    {
         IdentityResult rc = new IdentityResult();
    
        if ((userManager != null) && (userEmail != null) && (context != null) )
        {
            var user = await userManager.FindByEmailAsync(userEmail);
            var logins = user.Logins;
            var rolesForUser = await userManager.GetRolesAsync(user);
    
            using (var transaction = context.Database.BeginTransaction())
            {
              foreach (var login in logins.ToList())
              {
                await userManager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey);
              }
    
              if (rolesForUser.Count() > 0)
              {
                foreach (var item in rolesForUser.ToList())
                {
                  // item should be the name of the role
                  var result = await userManager.RemoveFromRoleAsync(user, item);
                }
              }
              rc = await userManager.DeleteAsync(user);
              transaction.Commit();
            }
        }
        return rc;
    }
    

Exemple d'appel - le formulaire passe le mot de passe de l'utilisateur (texte clair) dans le modèle:

        // POST: /Manage/DeleteUser
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteUser(DeleteUserViewModel account)
    {
        var user = await GetCurrentUserAsync();
        if ((user != null) && (user.PasswordHash != null) && (account != null) && (account.Password != null))
        {
            var hasher = new Microsoft.AspNetCore.Identity.PasswordHasher<ApplicationUser>();
            if(hasher.VerifyHashedPassword(user,user.PasswordHash, account.Password)  != PasswordVerificationResult.Failed)
            {
                IdentityResult rc = await AccountController.DeleteUserAccount( _userManager, user.Email, _Dbcontext); 
                if (rc.Succeeded)
                {
                    await _signInManager.SignOutAsync();
                    _logger.LogInformation(4, "User logged out.");
                    return RedirectToAction(nameof(HomeController.Index), "Home");
                }
            }
        }
        return View(account);
    }
2
wpqs

Je cherchais aussi la réponse, mais finalement c’est ce qui fonctionne bien pour moi, même son ancien poste, mais il peut être utile pour quelqu'un.

// GET: Users/Delete/5
    public ActionResult Delete(string id)
    {

        using (SqlConnection sqlCon = new SqlConnection(connectionString))
        {
            sqlCon.Open();

            string query = "DELETE FROM AspNetUsers WHERE Id = @Id";
            SqlCommand sqlCmd = new SqlCommand(query, sqlCon);
            sqlCmd.Parameters.AddWithValue("@Id", id);
            sqlCmd.ExecuteNonQuery();
        }

        return RedirectToAction("Index");
    }

    // POST: Users/Delete/5
    [HttpPost]
    public ActionResult Delete(string id, FormCollection collection)
    {
        try
        {
            // TODO: Add delete logic here

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
0
Alik