当用户在 Blazor Webassembly 身份验证和授权中具有多个角色时出现问题?

Posted

技术标签:

【中文标题】当用户在 Blazor Webassembly 身份验证和授权中具有多个角色时出现问题?【英文标题】:Problem when user has multi roles in Blazor Webassembly authentication and authorisation? 【发布时间】:2021-10-23 21:28:32 【问题描述】:

我有一个 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));
    

Startup.cs

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

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

【问题讨论】:

如果您已经拥有同名声明,请登录登录 想你,...如果我用一个用户登录没有问题!... 您好,zekad,如果答案解决了您的问题,请将其标记为正确答案,以便对未来的用户有所帮助。 嗨 Nicola,非常感谢您的回答,您的回答是正确且合乎逻辑的,但我现在无法设置正确的代码...... 【参考方案1】:

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

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

所以你需要修改该行

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

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

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

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


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

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

【讨论】:

以上是关于当用户在 Blazor Webassembly 身份验证和授权中具有多个角色时出现问题?的主要内容,如果未能解决你的问题,请参考以下文章

Blazor WebAssembly - 用户帐户和身份服务器的最佳实践

在 Blazor WebAssembly 中获取第三方登录的用户数据

如何在 blazor webassembly 项目中对服务器端控制器中的用户进行身份验证?

Blazor WebAssembly 与身份服务器通过表单传递用户名

钉钉PC端使用 Blazor WebAssembly 读取用户信息

重定向到 Blazor WebAssembly 中的 403 禁止组件