asp.net-mvc ASP.NET MVC 5 如何在 Identity 2.0 中删除用户及其相关数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23977036/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC 5 how to delete a user and its related data in Identity 2.0
提问by Franva
Hi I'm following this article to delete a user in Identity 2.0 http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-details-and-delete-methods
嗨,我正在按照这篇文章删除 Identity 2.0 中的用户 http://www.asp.net/mvc/tutorials/mvc-5/introduction/examing-the-details-and-delete-methods
However, I need to delete all related records in AspNetUserRoles first and then delete the user.
但是,我需要先删除AspNetUserRoles中的所有相关记录,然后再删除用户。
I found an example which is written in Identity 1.0 and some of methods used inside this example don't exist.
我发现了一个用 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();
}
}
I cannot find IdentityManagerfrom anywhere, and context.Usersdoesn't have FindAsync()method either.
我IdentityManager从任何地方都找不到,context.Users也没有FindAsync()方法。
Please help to figure out how to properly delete a User and its related records in Identity 2.0
请帮助弄清楚如何在 Identity 2.0 中正确删除用户及其相关记录
Thanks.
谢谢。
回答by Horizon_Net
I think the classes you're looking for are the UserManagerand the RoleManager. In my opinion they are the better way instead of going against the context directly.
我认为您正在寻找的类是UserManager和RoleManager。在我看来,它们是更好的方法,而不是直接违背上下文。
The UserManagerdefines a method RemoveFromRoleAsyncwhich gives you the ability to remove the user (identified by his key) from a given role. It also defines several Find methods, such as FindAsync, FindByIdAsync, FindByNameAsync, or FindByEmailAsync. They all can be used to retrieve a user. To delete a user you should use the DeleteAsyncmethod which accepts a user object as a parameter. To get the roles a user is member of Identity gives you the GetRolesAsyncmethod where you pass in the ID of the user. Also I see that you're trying to remove a login from a user. For this purpose you should use the RemoveLoginAsyncmethod.
该的UserManager定义了一个方法RemoveFromRoleAsync,让你删除的用户从给定角色的能力(通过他的主要标识)。它还定义了多个 Find 方法,例如FindAsync、FindByIdAsync、FindByNameAsync或FindByEmailAsync。它们都可用于检索用户。要删除用户,您应该使用接受用户对象作为参数的DeleteAsync方法。要获取用户是 Identity 成员的角色,您可以使用GetRolesAsync方法,您可以在该方法中传入用户的 ID。我还看到您正在尝试从用户中删除登录名。为此,您应该使用RemoveLoginAsync方法。
All in all your code would look similar to the following one:
总而言之,您的代码将类似于以下代码:
// 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();
}
}
You'll need to adjust this snippet to your needs, because I don't have an idea how your IdentityUserimplementation looks like. Remember to declare the UserManageras needed. An example how you could do this can be found when you create a new project in Visual Studio using Individual Accounts.
您需要根据需要调整此代码段,因为我不知道您的IdentityUser实现是什么样的。请记住根据需要声明UserManager。当您使用Individual Accounts在 Visual Studio 中创建新项目时,可以找到如何执行此操作的示例。
回答by wpqs
- Brad's point about requiring @Html.AntiForgeryToken() in views is not necessary if you are using latest versions of ASP.NET - see AntiForgeryToken still required
- Why not create a SQL trigger for AspNetUsers so deleting a user also deletes the corresponding records for user from AspNetUserRoles and AspNetUserLogins?
I need to invoke DeleteUser from a number of places so I added a static method to AccountController (see below). I'm still learning about MVC, so should be grateful for comments, in particular 1) use of IdentityResult as a return code 2) wisdom of extending AccountController in this way 3) approach for putting password (cleartext) into the Model to validate the action (see sample 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; }
- 如果您使用的是最新版本的 ASP.NET,则不需要在视图中使用 @Html.AntiForgeryToken() 的 Brad 观点 - 请参阅仍需要 AntiForgeryToken
- 为什么不为 AspNetUsers 创建一个 SQL 触发器,这样删除用户也会从 AspNetUserRoles 和 AspNetUserLogins 中删除用户的相应记录?
我需要从多个地方调用 DeleteUser,所以我向 AccountController 添加了一个静态方法(见下文)。我仍在学习 MVC,所以应该感谢评论,特别是 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; }
Sample invocation - form passes the user's password (cleartext) in Model:
示例调用 - 表单在模型中传递用户的密码(明文):
// 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);
}
回答by wpqs
Update for ASP.NET Core 2.0 - hope this saves someone a bit of time
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
}
}
回答by Alik
I was looking also for the answer but finally this is what work well for me, even its old post but it may help for someone.
我也在寻找答案,但最终这对我来说很有效,即使是旧帖子,但它可能对某人有所帮助。
// 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();
}
}

