【问题标题】:How to Validate JwtSecurityToken Custom Property如何验证 JwtSecurityToken 自定义属性
【发布时间】:2020-04-18 04:26:17
【问题描述】:

我正在尝试将自定义属性添加到在 ASP.NET Core Web API (3.1) 中生成的不记名令牌。我目前有一个运行良好的登录过程,它将发出一个用于授权请求的不记名令牌。我可以看到一个问题,如果有人破解用户名并通过,他们将拥有有效的 JWT 并可以访问我的 api。

我正在将此 API 用于移动应用 (flutter),并希望增加额外的安全性。使用颤振/飞镖,我可以访问一个唯一的设备 ID。我希望在不记名令牌中包含设备 ID,并根据请求从发出的 JWT 中提取设备 ID,并从 DEVICE_ID 请求标头值中对其进行验证,以确认它来自最初请求并生成 JWT 的同一设备.

我的第一个问题是我该怎么做?我找到了一篇关于 Payload (token.Payload["custom prop"] = ...) 的帖子 here,但我如何在授权期间提取它?有没有更好的不同方法来实现这一点?

我希望保留验证,这样我就可以简单地继续使用我的 api 控制器方法上方的 [Authorize] 属性。

这是我的启动 ConfigureServices 方法

 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = Configuration["Jwt:Issuer"],
                        ValidAudience = Configuration["Jwt:Issuer"],
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])),

                    };
                });

这里是我生成令牌的地方:

 private string GenerateJSONWebToken(UserModel user)
        {
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(JwtRegisteredClaimNames.Email, user.Email),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            };

            var token = new JwtSecurityToken(
                issuer: _config["Jwt:Issuer"],
                audience: _config["Jwt:Issuer"],
                claims,
                expires: DateTime.Now.AddMinutes(120),
                signingCredentials: credentials);
            token.Payload["DEVICE_ID"] = 1001; // Added here just as example of Payload
            var encodeToken = new JwtSecurityTokenHandler().WriteToken(token);
            return encodeToken;
        }

这里有一些只需要[Authorize]属性自动拒绝错误请求的地方方法:

        [Authorize]
        [HttpPost("Post")]
        public string Post()
        {
            var identity = HttpContext.User.Identity as ClaimsIdentity;
            IList<Claim> claim = identity.Claims.ToList();
            var userName = claim[0].Value;
            return "Welcome To: " + userName;
        }
        [Authorize]
        [HttpGet("GetValue")]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "Value1", "Value2", "Value3" };
        }

我使用 this 在线教程为 API 构建了 JWT 授权。谢谢你的帮助。

我刚刚找到this (Microsoft: TokenValidationParameters.PropertyBag 并试图找到一些示例。在文档中它说“包含自定义键/值对的集合。这允许添加可用于自定义令牌验证场景的参数。”

【问题讨论】:

    标签: authentication asp.net-core asp.net-web-api flutter jwt


    【解决方案1】:

    您可以使用这样的负载来使用自定义声明:

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
        new Claim(JwtRegisteredClaimNames.Email, user.Email),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim("device_id", "smaple_id")); // custom property claim
    };
    

    现在这里是一种简单的方法,而不是使用中间件创建自定义令牌验证器。

    app.UseAuthentication();
    app.Use(async (context, next) =>
    {
        var deviceId = context.User.Claims.SingleOrDefault(x => x.Type == "device_id");
        var validationResult = DoSomeValidation(deviceId)
        if (validationResult == false)
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Unauthorized Device");
        }
        await next.Invoke();
    });
    

    要获得更简洁的代码,请在扩展方法中使用 from middleware。

    【讨论】:

      【解决方案2】:

      Claims-Based authorization 是使用自定义声明的便捷方式。在您的 Startup.cs 中,您可以输入以下内容:

      services.AddAuthorization(options =>
      {
        options.AddPolicy("policy1", policy => policy.RequireClaim("CustomClaimName", "Accepted Value"));
      });
      

      然后在您的控制器中,您可以在要保护的方法中添加:

      [Authorize(Policy = "policy1")]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多