3

I have a .NET Core 2.0 Web API. I am using Jwt authentication on it.

Whenever the application reaches this line, an exception is thrown:

var userClaims = await _userManager.GetClaimsAsync(user);

The exception is:

System.InvalidOperationException: Sequence contains more than one matching element

What is weird is that this wasn't happening before, it started happening when I upgraded to .NET Core 2.0 from 1.1.

The Seed method for the database is below:

public async Task Seed()
{
  var adminUserJ = await _userManager.FindByNameAsync("Ciwan");
  var regularUser = await _userManager.FindByNameAsync("John");

  if (adminUserJ == null)
  {
    if (!await _roleManager.RoleExistsAsync("Admin"))
    {
      var role = new IdentityRole("Admin");
      role.Claims.Add(new IdentityRoleClaim<string> { ClaimType = "IsAdmin", ClaimValue = "True" });
      await _roleManager.CreateAsync(role);
    }

    adminUserJ = new BbUser
    {
      UserName = "Ciwan",
      Email = "ck83s9@gmail.com"
    };

    var userResult = await _userManager.CreateAsync(adminUserJ, "Welcome123");
    var roleResult = await _userManager.AddToRoleAsync(adminUserJ, "Admin");
    var claimResult = await _userManager.AddClaimAsync(adminUserJ, new Claim("Points", "10"));

    if (!userResult.Succeeded || !roleResult.Succeeded || !claimResult.Succeeded)
    {
      throw new InvalidOperationException("Failed to build user and roles");
    }
  }

  if (regularUser == null)
  {
    if (!await _roleManager.RoleExistsAsync("Regular"))
    {
      var role = new IdentityRole("Regular");
      role.Claims.Add(new IdentityRoleClaim<string> { ClaimType = "IsRegular", ClaimValue = "True" });
      await _roleManager.CreateAsync(role);
    }

    regularUser = new BbUser
    {
      UserName = "John",
      Email = "j.watson@world.com"
    };

    var userResult = await _userManager.CreateAsync(regularUser, "BigWow321");
    var roleResult = await _userManager.AddToRoleAsync(regularUser, "Regular");
    var claimResult = await _userManager.AddClaimAsync(regularUser, new Claim("Points", "10"));

    if (!userResult.Succeeded || !roleResult.Succeeded || !claimResult.Succeeded)
    {
      throw new InvalidOperationException("Failed to build user and roles");
    }
  }

  _context.AddRange(GetListOfArtists(adminUserJ.Id, regularUser.Id));
  await _context.SaveChangesAsync();
}

I can't see anything wrong. I tried looking at the AspNetUserClaims table in the database, but all seems OK. I have 2 claims in there, one for each user.

This error happens when I attempt to log in a user, so the request arrives here:

[HttpPost("auth/token")]
public async Task<IActionResult> CreateToken([FromBody] CredentialsDto credentials)
{
  try
  {
    var user = await _userManager.FindByNameAsync(credentials.Username);
    if (user != null)
    {
      if (IsUserPasswordValid(credentials, user))
      {
        var claims = await GetClaimsAsync(user);
        var token = CreateNewJwtToken(claims);

        return Ok(new
        {
          token = new JwtSecurityTokenHandler().WriteToken(token),
          expiration = token.ValidTo
        });
      }
    }
  }
  catch (Exception exception)
  {
    Console.WriteLine(exception);
    throw;
  }
  return BadRequest("Failed to generate token!");
}

private async Task<IEnumerable<Claim>> GetClaimsAsync(BbUser user)
{
  var userClaims = await _userManager.GetClaimsAsync(user);
  return new[] {
          new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
          new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
  }.Union(userClaims);
}
J86
  • 14,345
  • 47
  • 130
  • 228
  • can you shows that webapi Methods associated with the call to `var userClaims = await GetClaimsAsync(user)` – mvermef Dec 30 '17 at 01:02
  • Thanks @mvermef, I've added that code. – J86 Dec 30 '17 at 01:22
  • are you rolling your own security are you using something like IdentityServer? – mvermef Dec 30 '17 at 02:30
  • IdentityServer is what I am using – J86 Dec 30 '17 at 09:24
  • What type is `_userManager` ? – huysentruitw Dec 30 '17 at 12:59
  • It is of type `private readonly UserManager _userManager;`. Do I need to update all my IdentityServer stuff when I upgrade to .NET Core 2.0? Could that be the issue? – J86 Dec 30 '17 at 13:17
  • There were breaking changes in Core 2, with identity and Entity Framework Core, related to Roles and Users, they took out the navigation properties respective. Other than that it shouldn't be an issue, but is IdentityServer used integrated or separate? Also I assume `UserManager` is being injected? IdentityServer4 (.net core 2) is what I am using, I haven't seen this but I am not creating my own tokens letting IdentityServer do it. Not sure why you reinventing the wheel – mvermef Dec 30 '17 at 16:32
  • To be clear they give you everything you need for the tokens, if you need claims included IProfileService has to be implemented. Scopes / Api Resources have to exist. When I say that I am using the Sql persisted setup with IS4 – mvermef Dec 30 '17 at 16:38
  • @mvermef elaborate on how I am reinvesting the wheel please? What should I be doing? – J86 Dec 30 '17 at 16:55
  • maybe I am confused, but why are you creating a api/auth/token route when the IS4 pipeline already looks for `http://hostname/connect/token` which takes a standard post with credentials and scopes, with the setup associated to the docs. – mvermef Dec 30 '17 at 18:44
  • I didn't get a `http://hostname/connect/token` route when I created my application (initially in .NET Core v1.1) – J86 Dec 30 '17 at 22:22
  • 2
    @mvermef It seems that Ciwan isn't using IdentityServer4 at all. There is no code where IdentityServer4 is configured.Check his other questions. I think the IdentityServer4 flag should be removed. –  Dec 31 '17 at 12:28
  • @RuardvanElburg is right. I was confused, and this helped [clear things up for me](https://stackoverflow.com/questions/42121854/net-core-identity-server-4-authentication-vs-identity-authentication). Still have the issue though, but now with `Microsoft.AspNetCore.Identity` – J86 Dec 31 '17 at 12:30
  • `BbUser` is the class that inherits IdentityUser? If so when you created the DB initially with the initial migration (stretch here assuming migrations are used), was the pipeline configured with `BbUser` as the class in the configuration in `startup.cs` or was it `IdentityUser` (the default) – mvermef Dec 31 '17 at 20:38
  • I really suggest instead of rolling your own tokens to have http://IdentityServer.io doing the heavy lifting, literally nothing than a few pipeline changes to incorporate it. – mvermef Dec 31 '17 at 20:40
  • @mvermef can you point me to an article that makes use of IdentityServer 4 with a .NET Core app? – J86 Jan 01 '18 at 13:55
  • I will post my `startup.cs` that has some of the pipeline setup for using bearer tokens – mvermef Jan 02 '18 at 10:34
  • Hi @Ciwan and others wondering if you got any solution for this problem? I'm facing same issue after upgrading my project from .NET Core 1.2 to 2.0 – Sameer Awate Jul 04 '18 at 17:11

0 Answers0