Bmo*_*moe 2 c# authentication asp.net-authorization jwt asp.net-core
我将我的应用程序从 .NET Core 2.2 升级到 .NET Core 3.1。当我尝试使用 PostMan 测试我的端点时,我注意到收到 401 Unauth 错误。当我查看标题时,我发现到期时间无效:
我获取了以下不记名令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQm9iIiwibmJmIjoiMTYxNzk3Nzg1MSIsImV4cCI6IjE2MjMxNjE4NTYiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiQmFza2V0YmFsbCIsIlJ1Z2J5IiwiRm9vdGJhbGwiXX0.QRLuXFeopf7QZ1NUzWcctuSfnNXiPgc2UH7NxAuHYvw
我正在生成令牌端点并使用jwt.io对其进行解码,exp 字段为“1623161856”。
 我将其转换为 Javascript 中的日期对象,它等于未来 60 天。
我将其转换为 Javascript 中的日期对象,它等于未来 60 天。

所以token肯定没有过期。不确定我在升级到 .NET Core 3.1 时是否遗漏了任何内容,但这里是相关代码:
在Startup.cs我有
   public void ConfigureServices(IServiceCollection services)
    {
        // Initial Setup
        services.AddMvc();
        services.AddSingleton<IConfiguration>(Configuration);
        // Call this in case you need aspnet-user-authtype/aspnet-user-identity
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        // Register the Swagger generator, defining one or more Swagger documents 
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc(Configuration["v1"], new OpenApiInfo { Title = Configuration["Sports"], Version = Configuration["v1] });
        });
        services.AddDataProtection();
        
        //Authentication Setup
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromMinutes(5)
            };
            options.SaveToken = true;
            options.Events = new JwtBearerEvents()
            {
                OnTokenValidated = context =>
                {
                    var accessToken = context.SecurityToken as JwtSecurityToken;
                    if (accessToken != null)
                    {
                        ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
                        if (identity != null)
                        {
                            identity.AddClaim(new Claim("access_token", accessToken.RawData));
                        }
                    }
                    return Task.CompletedTask;
                }
            };
        });
        services.AddAuthorization();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/" + Configuration["v1"] + "/swagger.json", Configuration["Sports"]);
        });
        
        app.UseStaticFiles();
        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapControllerRoute("swagger", "swagger/");
        });
        app.UseWelcomePage("/swagger");
    }
该令牌是由我的 api 端点之一生成的。该代码如图所示:
 [HttpPost("SportApi/Token")]
    [ServiceFilter(typeof(SportResourceFilter))]
    public IActionResult Create(string key)
    {
       return new ObjectResult(GenerateToken(key));
    }
 private string GenerateToken(string someKey)
    {
        JwtSecurityToken token = new JwtSecurityToken();
        List<SportAPIKey> ro = new List<SportAPIKey>();
        if (!string.IsNullOrEmpty(someKey))
        {
            using (StreamReader r = new StreamReader("keys.json"))
            {
                string json = r.ReadToEnd();
                ro = JsonConvert.DeserializeObject<List<SportAPIKey>>(json);
            }
            
            if (ro.Exists(sak => sak.SportAPIKeyValue.Equals(someKey)))
            {
                SportAPIKey sportapikey = ro.Find(sak => sak.SportAPIKeyValue.Equals(someKey));
                List<Claim> lc = new List<Claim>();
                Claim claimClient = new Claim(ClaimTypes.Name, sportapikey.Client);
                lc.Add(claimClient);
                foreach (string team in sportapikey.Teams)
                    {
                        lc.Add(new Claim(ClaimTypes.System, team.Trim()));
                    }
                Claim claimEffDate = new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString());
                lc.Add(claimEffDate);
                int tokenLifespan = 60;
                Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
                lc.Add(claimExpDate);
                foreach (string sport in sportapikey.Sports.Split(","))
                {
                    lc.Add(new Claim(ClaimTypes.Role, sport.Trim()));
                }
                var claims = lc.ToArray();
                
                token = new JwtSecurityToken(
                    new JwtHeader(new SigningCredentials(
                        new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
                                                 SecurityAlgorithms.HmacSha256)),
                    new JwtPayload(claims));
            }
        }
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
您的令牌包含时间戳nbf和exp字符串:
  "nbf": "1617977851",
  "exp": "1623161856",
这是无效的。在 https:\jwt.io 上,当您将鼠标悬停在这些值上时,您会发现出现了问题。通常它显示时间戳,但在您的示例中它显示:“无效日期”:
JWT 中的时间戳应该是数值:
NumericDate
一个 JSON 数值,表示从 1970-01-01T00:00:00Z UTC 到指定 UTC 日期/时间的秒数
这些值本身是正确的:
在生成声明期间发生错误:
  "nbf": "1617977851",
  "exp": "1623161856",
相反,请使用此构造函数,它允许您设置ClaimValueType:
new Claim(JwtRegisteredClaimNames.Exp, 
          new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString(), 
          ClaimValueTypes.Integer64)
或者更好的是,让框架使用此构造函数为您添加过期时间戳:
public JwtSecurityToken (string issuer = default, string audience = default, System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> claims = default, DateTime? notBefore = default, DateTime? expires = default, Microsoft.IdentityModel.Tokens.SigningCredentials signingCredentials = default);
例如:
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, 
                               new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);
| 归档时间: | 
 | 
| 查看次数: | 1193 次 | 
| 最近记录: |