【问题标题】:ASP.NET Identity UserManager UpdateAsync Removing RolesASP.NET Identity UserManager UpdateAsync 删除角色
【发布时间】:2018-08-15 11:51:45
【问题描述】:

我们的应用程序中有一个屏幕允许管理员角色的成员编辑用户帐户详细信息。

最终,任何用户对象都会发送到服务器并使用以下方式更新:

await userManager.UpdateAsync(user);

这在更新用户记录时按预期工作。我们可以进行持久化到数据库的更改,例如用户名、电话号码等。

我看到的问题是,有时更新角色而不是向用户添加其他角色时,它会删除所有角色。

在我们的 ApplicationUser 对象上,我们有这样的属性:

public virtual ICollection<IdentityUserRole<string>> Roles { get; set; } = new List<IdentityUserRole<string>>();

因此,我们可以将客户端和服务器之间的角色作为用户对象的一部分反弹。

我正在努力理解的是我看到的 userManager.UpdateAsync(user); 方法的不一致行为。它显然有效,否则永远无法向用户添加任何角色。

每次提交时,到达服务器的对象都会正确填充角色。基本流程是:

  1. 添加角色并提交
  2. 角色已正确添加到用户
  3. 添加其他角色并提交
  4. 所有角色均已删除

如何防止它删除角色?

谢谢!

更新

正如@amirani 的回答中所详述的那样,我尝试过滤现有列表。我已经设置 AutoMapper 完全忽略该属性。

.ForMember(x => x.Roles, opt => opt.Ignore());

我现在只是像这样过滤(目前只添加):

foreach (var userDtoRole in userDto.Roles)
{
  if (user.Roles.FirstOrDefault(x => x.RoleId == userDtoRole) == null)
  {
    user.Roles.Add(new IdentityUserRole<string> {RoleId = userDtoRole, UserId = user.Id });
  }
}

其他角色永远不会添加到基础数据库中。在执行 UpdateUser 方法之前,我已经确认正在更新的用户对象具有正确的角色列表。

【问题讨论】:

  • 查看我的答案并与我们分享如何使用这些代码重现您的问题。

标签: c# asp.net-core asp.net-core-identity


【解决方案1】:

当您调用await userManager.UpdateAsync(user);时,您正在更新用户模型及其所有相关数据。您需要将新角色添加到现有角色列表中,而不是创建新的空列表并添加新记录。

【讨论】:

  • 我已经尝试过这种方法,告诉AutoMapper 忽略此属性,现在我正在过滤列表(根据 id 添加、删除)我看到了同样的问题。
【解决方案2】:

尝试下面的代码添加新角色

private readonly ApplicationDbContext _context;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<IdentityRole> _roleManager;
    public HomeController(ApplicationDbContext context
        , UserManager<ApplicationUser> userManager
        , RoleManager<IdentityRole> roleManager)
    {
        _context = context;
        _userManager = userManager;
        _roleManager = roleManager;
    }
    public async Task<IActionResult> CreateUserAndRole()
    {
        await _userManager.CreateAsync(new ApplicationUser { UserName = "test@outlook.com", Email = "test@outlook.com" });
        await _roleManager.CreateAsync(new IdentityRole {  Name = "Admin" });
        await _roleManager.CreateAsync(new IdentityRole { Name = "Administrator" });
        return Ok();
    }
    public async Task<IActionResult> AddAdminRoleToUser()
    {
        ApplicationUser user = _context.Users.FirstOrDefault(u => u.UserName == "test@outlook.com");
        var role = await _roleManager.FindByNameAsync("Admin");
        user.Roles.Add(new IdentityUserRole<string> { RoleId = role.Id, UserId = user.Id });
        await _userManager.UpdateAsync(user);
        return Ok();
    }
    public async Task<IActionResult> AddAdministratorRoleToUser()
    {
        ApplicationUser user = _context.Users.FirstOrDefault(u => u.UserName == "test@outlook.com");
        var role = await _roleManager.FindByNameAsync("Administrator");
        user.Roles.Add(new IdentityUserRole<string> { RoleId = role.Id, UserId = user.Id });
        await _userManager.UpdateAsync(user);
        return Ok();
    }

【讨论】:

  • 我们不会在控制器中公开这种粒度级别。您上面包含的代码在功能上与我正在使用的导致问题的代码相同。
  • 放在控制器里是用来调用的,你可以放在任何地方。你能在一个新的 MVC 项目中用上面的代码重现吗?与我们分享重现您的问题的详细方法。
猜你喜欢
  • 2019-07-21
  • 2014-09-11
  • 1970-01-01
  • 2015-03-19
  • 2016-08-06
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多