为什么我的授权 JWT 在发送到 Web API 时失败?

Why my authorization JWT is failing when is sent to the Web API?

好吧,我正在努力将我的 JWT 发送到 Web API,我需要调试方面的帮助。我正在使用 Angular 10 客户端和 ASP.NET Core 2.2 作为服务器。我的身份验证流程如下所示:

向客户端发送一个在服务器中生成的令牌,如下所示:

Claim[] claims = new[] {
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(now).ToUnixTimeSeconds().ToString())
                    // TODO: add additional claims here
                    };

                int tokenExpirationMins = _configuration.GetValue<int>("Auth:JsonWebToken:TokenExpirationInMinutes");
                SymmetricSecurityKey issuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Auth:JsonWebToken:Key"]));

                JwtSecurityToken token = new JwtSecurityToken(
                    issuer: _configuration["Auth:JsonWebToken:Issuer"],
                    audience: _configuration["Auth:JsonWebToken:Audience"], claims: claims, notBefore: now,
                    expires: now.Add(TimeSpan.FromMinutes(tokenExpirationMins)), signingCredentials: new SigningCredentials( issuerSigningKey, SecurityAlgorithms.HmacSha256));
                string encodedToken = new JwtSecurityTokenHandler().WriteToken(token);

                // build & return the response
                TokenResponseViewModel response = new TokenResponseViewModel()
                {
                    Token = encodedToken,
                    Expiration = tokenExpirationMins,
                    Email = user.Email,
                    User = user.UserName
                };
                return Json(response);

这很好,客户端从 TokenResponseViewModel 获取所有数据。

并且当客户端需要向我的 api/user/test 端点发送 API 请求时,它没有经过身份验证。请注意,这只是我试验的一个终点。它是这样保护的:

/// <summary>
        /// POST: api/user/test
        /// </summary>
        /// <returns>Status code.</returns>
        [HttpGet("Test")]
        [Authorize]
        public IActionResult GetTest()
        {
            return new OkObjectResult(new { Message = "This is secure data!" });
        }

我的请求看起来不错。下面是 headers 和请求数据:

并且由于请求未通过 API 的身份验证,它正在尝试重定向到 http://localhost:50962/Account/Login?ReturnUrl=/api/user/test

目前我不知道如何解决这个问题。 Token 貌似没问题,但是被Identity框架拒绝了。 JWT 不会过期,因为过期时间设置为 100 分钟。

下面也是我的Angular请求电话:

executeCall(): void {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': 'bearer ' + this.auth.getAuth()!.token
      })
    };

    console.log('executing call');
    var url = 'http://localhost:50962/' + 'api/user/test';
    this.http.get<string>(url, httpOptions)
      .subscribe(
        (val) => {
          console.log("POST call successful value returned in body", val);
        },
        response => {
          console.log("POST call in error", response);
          //todo: popup
        },
        () => {
          console.log("The POST observable is now completed.");
          //todo: popup
        });
  }

Startup.cs 身份验证设置:

services.AddAuthentication(opts =>
            {
                opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(cfg =>
            {
                cfg.RequireHttpsMetadata = false;
                cfg.SaveToken = true;
                cfg.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidIssuer = Configuration["Auth:Jwt:Issuer"],
                    ValidAudience = Configuration["Auth:Jwt:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Auth:Jwt:Key"])),
                    ClockSkew = TimeSpan.Zero,
                    RequireExpirationTime = true,
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = true,
                    ValidateAudience = true
                };
            })

应用程序设置 配置:

"JsonWebToken": {
      "Issuer": "http://localhost:50962/",
      "Audience": "http://localhost:50962/",
      "Key": "0pvUGXcvhg1ZRQZGBGy4",
      "TokenExpirationInMinutes": 100
    }

问题出在这段代码上,我不得不将 Authorize 替换为 Authorize(AuthenticationSchemes = "Bearer"):

/// <summary>
        /// POST: api/user/test
        /// </summary>
        /// <returns>Status code.</returns>
        [HttpGet("Test")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        public IActionResult GetTest()
        {
            return new OkObjectResult(new { Message = "This is secure data!" });
        }

基于this article.