【问题标题】:Authorize not working for roles using ASP.NET Core 3.1 Identity with MongoDB授权不适用于使用 ASP.NET Core 3.1 Identity 和 MongoDB 的角色
【发布时间】:2021-02-27 16:15:49
【问题描述】:

更新:不只是管理员角色不起作用 - 似乎任何需要授权的路由都返回 401。

我想创建一个管理员角色来控制对我的 AdminController 的访问。我的堆栈是用于 API/Angular 9 前端的 MongoDb/.NET Core(3.1)。

我用角色为我的数据库播种

        private static void SeedRoles(RoleManager<MongoRole> roleManager)
        {
            if (!roleManager.RoleExistsAsync("User").Result)
            {
                MongoRole role = new MongoRole();
                role.Name = "User";
                IdentityResult roleResult = roleManager.
                CreateAsync(role).Result;
            }


            if (!roleManager.RoleExistsAsync("Admin").Result)
            {
                MongoRole role = new MongoRole();
                role.Name = "Admin";
                IdentityResult roleResult = roleManager.
                CreateAsync(role).Result;
            }
        }

在另一种种子方法中,我已将以下 2 个角色添加到我的用户帐户中

                    userManager.AddToRoleAsync(user, "User").Wait();
                    userManager.AddToRoleAsync(user, "Admin").Wait();

在我的启动文件中,我已经配置了我的 mongo 身份提供者

services.AddIdentityMongoDbProvider<AspNetCore.Identity.Mongo.Model.MongoUser, AspNetCore.Identity.Mongo.Model.MongoRole>(identityOptions =>
            {
                identityOptions.Password.RequiredLength = 6;
                identityOptions.Password.RequireLowercase = false;
                identityOptions.Password.RequireUppercase = false;
                identityOptions.Password.RequireNonAlphanumeric = false;
                identityOptions.Password.RequireDigit = false;
            }, mongoIdentityOptions => {
                mongoIdentityOptions.ConnectionString = **REMOVED CONN STR FROM HERE**;
            });

我在用户控制器中的登录方法从我的用户那里获取角色并将它们添加到声明列表中 - 据我所知,它可以包含在可以检查角色的令牌中。当我调试并在此方法上添加断点时,很明显角色正在添加到 claimList - 所以我不确定问题是否存在。

 // POST api/user/login
        [HttpPost]
        [AllowAnonymous]
        public async Task<ActionResult> Login([FromBody]LoginEntity model)
        {
            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false);
                if (result.Succeeded)
                {
                    string key = model.UserName + "ezgig321";
                    var appUser = _userManager.Users.SingleOrDefault(r => r.UserName == model.UserName);
                    var issuer = "ezgig";
                    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
                    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
                    var roles = await _userManager.GetRolesAsync(appUser);
                    var claimList = new List<Claim>();
                    foreach (var role in roles)
                    {
                        var roleClaim = new Claim(ClaimTypes.Role, role);
                        claimList.Add(roleClaim);
                    }
                    claimList.Add(new Claim("username", model.UserName));

                    //var token = AuthenticationHelper.GenerateJwtToken(model.Email, appUser, _configuration);
                    var token = new JwtSecurityToken(issuer, //Issure    
                                    issuer,  //Audience    
                                    claimList,
                                    expires: DateTime.Now.AddDays(1),
                                    signingCredentials: credentials);

                    var encodedJwt = new JwtSecurityTokenHandler().WriteToken(token);

                    var rootData = new LoginResponse(encodedJwt, appUser.UserName);
                    return Ok(rootData);
                }
                return StatusCode((int)HttpStatusCode.Unauthorized, "Bad Credentials");
            }
            string errorMessage = string.Join(", ", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
            return BadRequest(errorMessage ?? "Bad Request");
        }

然而,当我使用从以管理员角色登录到我的帐户返回的 JWT 时 - 当我尝试访问我放置在我的管理员控制器中的这个测试方法时,我仍然会收到 401 未授权。

    [Authorize(Roles ="Admin")]
    [Route("api/[controller]/[action]")]
    public class AdminController : Controller
    {
        // GET api/admin/admintest
        [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        [HttpGet]
        public  ActionResult AdminTest()
        {
            return Ok("you seem to have admin authorisation");
        }

【问题讨论】:

  • 客户端到服务器的连接使用 TLS 进行身份验证。默认 TLS 版本必须是 1.2/1.3。今年 6 月之前的旧代码允许使用 1.0/1.1。有关设置 TLS 1.2 的信息,请参阅以下内容:stackoverflow.com/questions/60863817/…
  • 这是我需要在客户端(角度)代码上更改的设置吗?因为我在使用邮递员时会遇到 401 - 将客户完全排除在流程之外
  • 我不能 100% 确定 Postman 的设置位置。我怀疑它来自您的浏览器设置。 TLS 的版本在您的浏览器设置中。尝试将设置更改为 disable1.0/1.1(和 SSL)并仅使用 1.2/1.3。
  • 我已经尝试过了,但仍然得到 401 - 而且我意识到我得到的不仅仅是管理策略的 401,而是任何需要授权的路由
  • 错误发生前多久?如果是 30 秒,您可能正在寻找代理,而 30 秒表示代理正在超时。您可以将代理设置为 null (client.Proxy = null)。您的 URL 是使用 HTTP 还是 HTTPS?尝试两者。在尝试使用 c# 之前让 Postman 工作。

标签: c# mongodb asp.net-identity mongodb-.net-driver


【解决方案1】:

原来只是愚蠢导致了这个错误。我在 Register/Login 端点的 issuer 和 JWT 关键变量中进行了硬编码,但我写错了。

因为它们与 startup.cs 文件中的 issuer/jwt 键不匹配(见下文)...


services.AddAuthentication(options =>
            {
                //Set default Authentication Schema as Bearer
                options.DefaultAuthenticateScheme =
                           JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme =
                           JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme =
                           JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(cfg =>
            {
                cfg.RequireHttpsMetadata = false;
                cfg.SaveToken = true;
                cfg.TokenValidationParameters =
                       new TokenValidationParameters
                       {
                           ValidIssuer = Configuration["JwtIssuer"],
                           ValidAudience = Configuration["JwtIssuer"],
                           IssuerSigningKey =
                        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
                           ClockSkew = TimeSpan.Zero // remove delay of token when expire
                       };
            });

这意味着 JWT 密钥因无效而被拒绝。对不起,如果有人在这上面浪费了任何时间。

【讨论】:

    猜你喜欢
    • 2020-09-24
    • 2020-03-13
    • 2020-08-27
    • 2020-03-02
    • 2021-03-12
    • 2021-09-04
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多