为什么将授权JWT发送到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请求发送到我的api/user/test端点时,该请求未经身份验证。请注意,这仅是我试用的机会。它是这样安全的:

/// <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!" });
        }

我的请求看起来不错。以下是标头和请求数据:

request

并且由于该请求未通过API认证,因此它正在尝试重定向http://localhost:50962/Account/Login?ReturnUrl=/api/user/test

enter image description here

目前,我不知道如何解决此问题。令牌似乎很好,但是被身份框架拒绝。 JWT未到期,因为到期时间设置为100min。

以下也是我的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