0

我有一个 Blazor Webassembly 解决方案,当我使用用户(具有多个角色)登录时,登录操作显示错误:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.ArgumentException: An item with the same key has already been added. Key: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
         at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
         at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
         at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
         at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
         at REMO.Server.Controllers.AuthController.CurrentUserInfo() in D:\REMO\REMO\Server\Controllers\AuthController.cs:line 87
         at lambda_method29(Closure , Object , Object[] )
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean&
isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

按照我的自定义身份验证提供程序

public class CustomStateProvider : AuthenticationStateProvider
{
        private readonly IAuthService api;
    private CurrentUser _currentUser;
    public CustomStateProvider(IAuthService api)
    {
        this.api = api;
    }
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var identity = new ClaimsIdentity();
        try
        {
                var userInfo = await GetCurrentUser();
                var roleClaims = identity.FindAll(identity.RoleClaimType);
                if (userInfo.IsAuthenticated)
                
                {
                var claims = new[] 
                { 
                   new Claim(ClaimTypes.Name, _currentUser.UserName)
                }
                .Concat(_currentUser.Claims.Select(c => new Claim(c.Key, c.Value)));
                    identity = new ClaimsIdentity(claims, "Server authentication");
                }
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine("Request failed:" + ex.ToString());
        }

        return new AuthenticationState(new ClaimsPrincipal(identity));
    }

启动.cs

...
    services.AddDbContext<ApplicationDBContext>(options => options .UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDBContext>();
...

问题似乎是一个身份存在多个角色。
如果身份只有一个角色,则不会出现问题。

4

1 回答 1

0

您的问题是角色声明密钥的构造。
这个键,如果是多个角色,必须是一个数组
您的 JWT 令牌中不能有多个“角色”键。

我认为您已经使用了Mukesh的代码并且是一个很好的起点,但是如果您阅读评论,最后一个解释了像您这样的问题。

所以你需要修改该行

.Concat(_currentUser.Claims.Select(c => new Claim(c.Key, c.Value)));

通过 LINQ 提取所有角色类型的声明并将它们添加到claims数组中。
现在您需要创建一个包含所有角色类型声明的数组(我认为它们来自您的 API)并添加一个数组类型的角色声明条目。

修改后我认为它应该可以工作。

生成的解码 JWT 令牌应具有以下形式:

{
   "sub": "nbiada",
   "jti": "123...",
   "role" : [
      "User",
      "Admin"
   ],
   "exp": 12345467,
...
}

注意:我已经缩短了role密钥,在您的实施中应该是http://schemas.microsoft.com/ws/2008/06/identity/claims/role

于 2021-08-24T05:38:42.183 回答