Search code examples
asp.net-coreasp.net-core-mvcasp.net-core-identity

"User security stamp cannot be null." error when adding/removing user roles in ASP.NET Core Identity


I am trying to add roles to a user if they do not match the ones that it already has and remove those that do match, but I am getting the following error:

User security stamp cannot be null.

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, User user, string[] roles)
{
    if (id != user.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            var listOfRoles = await privateUser.GetRolesAsync(user);

            foreach (var role in listOfRoles.Except(roles))
            {
                await privateUser.RemoveFromRoleAsync(user, role);
            }

            foreach (var role in roles.Except(listOfRoles))
            {
                await privateUser.AddToRoleAsync(user, role);
            }

            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!UserExists(user.Id))
            {
                return NotFound();
            }
            
            else
            {
                throw;
            }
        }

        return RedirectToAction(nameof(Index));
    }

    return View(user);
}

Solution

  • You're using a user obtained via a POST, which is not only bad practice, but won't even work here, because you're not posting the full User object. Namely, the value of SecurityStamp is missing, which is what the exception is telling you.

    Do not post the User. Instead, use the User.Id to fetch it from the database:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(string id, string[] roles)
    {
        var user = await _userManager.FindByIdAsync(id);
    
        if (user == null)
        {
            return NotFound();
        }
    
        // the rest of your code
    }
    

    UPDATE (for modifying user at the same time)

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(string id, User model, string[] roles)
    {
        var user = await _userManager.FindByIdAsync(id);
    
        if (user == null)
        {
            return NotFound();
        }
    
        // map over the values from "model" (i.e. the posted "User")
        // use "user", not "model" for role management functions
        user.FirstName = model.FirstName;
    
        // the rest of your code
    }