【问题标题】:ASP.NET MVC 5 how to delete a user and its related data in Identity 2.0ASP.NET MVC 5 如何在 Identity 2.0 中删除用户及其相关数据
【发布时间】:2014-07-21 12:54:51
【问题描述】:

我正在关注这篇文章以删除 Identity 2.0 中的用户 http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-details-and-delete-methods

但是,我需要先删除 AspNetUserRoles 中的所有相关记录,然后再删除用户。

我找到了一个用 Identity 1.0 编写的示例,并且此示例中使用的某些方法不存在。

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

我在任何地方都找不到IdentityManager,而且context.Users 也没有FindAsync() 方法。

如何在 Identity 2.0 中正确删除用户及其相关记录?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-5 asp.net-identity


    【解决方案1】:

    我认为您正在寻找的课程是UserManagerRoleManager。在我看来,它们是更好的方法,而不是直接违背上下文。

    UserManager 定义了一个方法RemoveFromRoleAsync,它使您能够从给定角色中删除用户(由他的密钥标识)。它还定义了几个 Find 方法,例如FindAsyncFindByIdAsyncFindByNameAsyncFindByEmailAsync。它们都可用于检索用户。要删除用户,您应该使用接受用户对象作为参数的DeleteAsync 方法。要获取用户是 Identity 成员的角色,您可以使用 GetRolesAsync 方法,在该方法中传入用户的 ID。我还看到您正在尝试从用户那里删除登录信息。为此,您应该使用RemoveLoginAsync 方法。

    您的所有代码看起来都类似于以下代码:

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

    您需要根据自己的需要调整这个 sn-p,因为我不知道您的 IdentityUser 实现是什么样的。请记住根据需要声明 UserManager。在 Visual Studio 中使用个人帐户创建新项目时,可以找到如何执行此操作的示例。

    【讨论】:

    • 嗨Horizo​​n_Net,我用同样的方法解决了这个问题。谢谢你的解释 :) 我其实不知道 IdentityUser 有什么用。
    • IdentityUser 是 Entity Framework 提供的基类(如果您使用它),用于根据您的需要自定义用户对象。基本实现为您提供了一些可以使用的基本属性,例如电子邮件地址或用户名。使用子类,您可以使用自己的属性对其进行扩展,例如名字或姓氏。在大多数教程和示例中,您会看到一个名为 ApplicationUser 的实现。如果你想了解更多,你绝对应该看看Scott Allen's blog
    • RemoveLoginAsync 需要两个参数。如果没有登录名和角色用户的 .ToList() ,我会收到一个异常,说 Enumerable 已被修改并且无法继续。我还需要将_userManager 更改为UserManager,但这似乎是我特有的。不同之处在于 UserManager 的 get 是 return _userManager ?? HttpContext.GetOwinContext().GetUserManager&lt;ApplicationUserManager&gt;(); 并且出于某种原因,如果不这样做 .FindByIdAsync(id) 将返回 null。
    • 另请注意,如果您要在视图中使用[ValidateAntiForgeryToken],那么您将在视图中使用need to include @Html.AntiForgeryToken()
    • 注意:if (rolesForUser.Count() &gt; 0)在角色删除之前是多余的foreach
    【解决方案2】:
    • 如果您使用的是最新版本的 ASP.NET,Brad 关于在视图中要求 @Html.AntiForgeryToken() 的观点是不必要的 - 请参阅 AntiForgeryToken still required
    • 为什么不为 AspNetUsers 创建一个 SQL 触发器,这样删除用户也会从 AspNetUserRoles 和 AspNetUserLogins 中删除用户的相应记录?
    • 我需要从多个地方调用 DeleteUser,因此我向 AccountController 添加了一个静态方法(见下文)。我还在学习 MVC,所以应该感谢 cmets,特别是 1)使用 IdentityResult 作为返回码 2)以这种方式扩展 AccountController 的智慧 3)将密码(明文)放入模型中以验证的方法操作(参见示例调用)。

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

    示例调用 - 表单在模型中传递用户密码(明文):

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

    【讨论】:

      【解决方案3】:

      ASP.NET Core 2.0 的更新 - 希望这可以节省一些时间

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

      【讨论】:

        【解决方案4】:

        我也在寻找答案,但最后这对我来说很有效,即使是它的旧帖子,但它可能对某人有所帮助。

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

        【讨论】:

        猜你喜欢
        • 2016-10-24
        • 1970-01-01
        • 2015-02-01
        • 2014-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多