【问题标题】:Role based Auth not working with Cookie based Authentication being developed using JWT Auth基于角色的身份验证不适用于使用 JWT 身份验证开发的基于 Cookie 的身份验证
【发布时间】:2020-12-21 03:11:17
【问题描述】:

我有一个 JWT 令牌从 API 返回到我的客户端应用程序,这是我的 JWT 代码:

var claims = new List<Claim>
                             {
                                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                                    new Claim(JwtRegisteredClaimNames.Sub, user.Email.ToString()),
                                    new Claim(ApplicationConstants.UserId, applicationUser.Id.ToString()),
                             };

                if (applicationUser.FirstName != null)
                {
                    claims.Add(new Claim(ApplicationConstants.FirstName, applicationUser.FirstName));
                }
                if (applicationUser.NormalizedUserName != null)
                {
                    claims.Add(new Claim(ApplicationConstants.UserName, applicationUser.NormalizedUserName));
                }

                //only if the user is vendor
                if (vendorUser != null) {
                    claims.Add(new Claim(RoleNameConstants.Vendor, vendorUser.Id.ToString()));
                    claims.Add(new Claim(ApplicationConstants.VendorId, vendorUser.VendorId.ToString()));
                }

                var claimsIdentity = new ClaimsIdentity(claims);

                //Adding UserClaims to JWT claims
                foreach (var item in userRoles)
                {
                    //claimsIdentity.AddClaim(new Claim(ApplicationConstants.Roles, item));
                    claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, item));
                }

                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret);

                #region code smell - don't look
                //var claims = new List<Claim>
                //{
                //    new Claim(JwtRegisteredClaimNames.Sub, user.Email),
                //    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                //    new Claim(JwtRegisteredClaimNames.Email, user.Email),
                //    new Claim("id", user.Id)
                //};

                //var userClaims = await _userManager.GetClaimsAsync(user);
                //claims.AddRange(userClaims);

                //var userRoles = await _userManager.GetRolesAsync(user);

                //foreach (var userRole in userRoles)
                //{
                //    claims.Add(new Claim(ClaimTypes.Role, userRole));

                //    var role = await _roleManager.FindByNameAsync(userRole);
                //    if (role == null) continue;
                //    var roleClaims = await _roleManager.GetClaimsAsync(role);

                //    foreach (var roleClaim in roleClaims)
                //    {
                //        if (claims.Contains(roleClaim))
                //            continue;

                //        claims.Add(roleClaim);
                //    }
                //}
                #endregion

                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(claimsIdentity),
                    //Expires = DateTime.UtcNow.Add(_jwtSettings.TokenLifetime),
                    Expires = DateTime.UtcNow.AddDays(30),
                    SigningCredentials =
                    new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
                };

                var token = tokenHandler.CreateToken(tokenDescriptor);

我正在使用它在 ASP.NET 身份中构建基于 cookie 的身份验证,如下所示:

var stream = response.Token;
            var handler = new JwtSecurityTokenHandler();
            var jsonToken = handler.ReadToken(stream);
            var token = handler.ReadToken(stream) as JwtSecurityToken;

            //my code
            var claims = new List<Claim>();

            foreach (var tokenClaim in token.Claims)
            {
                var claim = new Claim(tokenClaim.Type, tokenClaim.Value);
                claims.Add(claim);
            }

            var identity = new ClaimsIdentity(
                claims, CookieAuthenticationDefaults.AuthenticationScheme, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);

            //var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme, nameType, roleType);

            var principal = new ClaimsPrincipal(identity);

            var authProperties = new AuthenticationProperties
            {
                AllowRefresh = true,
                IsPersistent = userRequest == null ? false : userRequest.RememberMe,
                ExpiresUtc = token.ValidTo,
                IssuedUtc = DateTime.UtcNow
            };

            await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                principal,
                authProperties);

            _httpContextAccessor.AddCookie("token", response.Token, token.ValidTo);  
            //_sessionManager.SetString("token", response.Token);

            HttpContext.User = principal;
            _httpContextAccessor.HttpContext.User = principal;

现在这段代码可以正确地对用户进行身份验证,但是当我使用[Authorize(Roles = "Vendor,VendorAdmin")] 属性时,这对于角色的授权不能正常工作,即使用户拥有这些角色,它也不会让用户通过。

这是我的启动代码:

 services.AddAuthentication(x =>
            {

                x.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                x.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }/*CookieAuthenticationDefaults.AuthenticationScheme*/) // Sets the default scheme    to cookies
           .AddCookie(options =>
           {
               options.LoginPath = "/account/login";
               options.AccessDeniedPath = "/home/error";
           });

【问题讨论】:

  • this.User() 是什么?在代码中返回......它被授权了吗?
  • 您是否调试过以查看经过身份验证的用户的声明列表?它应该包含角色信息。否则肯定有问题不在 asp.net 核心框架方面。
  • @Hopeless 是的,它包含user.identity.claims中的角色声明
  • 您正在使用包含“schemas.microsoft.com/ws/2008/06/identity/claims/role”的 ClaimType.Role,请尝试改用声明“角色”。

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


【解决方案1】:

我测试了你的场景。从API获取的claim中角色的key为字符串role。

但是[Authorize(Roles = "Vendor,VendorAdmin")]中的Roles需要密钥http://schemas.microsoft.com/ws/2008/06/identity/claims/role。

然后在基于cookie的身份验证项目中重新添加角色。

        foreach (var tokenClaim in token.Claims)
        {
            if (tokenClaim.Type == "role")
            {
                claims.Add(new Claim(ClaimTypes.Role, tokenClaim.Value));
                continue;
            }
            var claim = new Claim(tokenClaim.Type, tokenClaim.Value);
            claims.Add(claim);
        }

然后就可以访问授权的方法了。

    [Authorize(Roles = "Vendor")]
    public IActionResult Resource()
    {
        return Ok();
    }

【讨论】:

  • @Zeeshan Adil,你能接受这个答案,还是有其他问题?
猜你喜欢
  • 2016-05-01
  • 2016-01-03
  • 2020-10-08
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
  • 2021-08-13
  • 2012-12-12
  • 1970-01-01
相关资源
最近更新 更多