在 ASP.NET Core MVC 中使用 JWT 进行身份验证的问题

问题描述 投票:0回答:1

我在 ASP.NET Core MVC 中使用 JSON Web Token (JWT) 实现身份验证时遇到问题。我有一个带有登录端点的 ASP.NET Core API,该端点返回 JWT 以响应用户登录。以下是 API 中我的登录端点的代码:

[HttpPost]
[Route("login")]
public async Task<IActionResult> Login([FromBody] LoginUserDTO userDTO)
{
    // ... (omission for brevity)
    return Accepted(new TokenRequest { Token = await _authManager.CreateToken(), RefreshToken = await _authManager.CreateRefreshToken() });
}    

public async Task<string> CreateToken()
{
    var signingCredentials = GetSigningCredentials();
    var claims = await GetClaims();
    var token = GenerateTokenOptions(signingCredentials, claims);

    return new JwtSecurityTokenHandler().WriteToken(token);
}

private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
{
    var jwtSettings = _configuration.GetSection("Jwt");
    var expiration = DateTime.Now.AddMinutes(Convert.ToDouble(
        jwtSettings.GetSection("lifetime").Value));

    var token = new JwtSecurityToken(
        issuer: jwtSettings.GetSection("Issuer").Value,
        claims: claims,
        expires: expiration,
        signingCredentials: signingCredentials
        );

    return token;
}

private async Task<List<Claim>> GetClaims()
{
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, _user.UserName)
    };

    var roles = await _userManager.GetRolesAsync(_user);

    foreach (var role in roles)
    {
        claims.Add(new Claim(ClaimTypes.Role, role));
    }

    return claims;
}

private SigningCredentials GetSigningCredentials()
{
    var key = _configuration.GetSection("Jwt:KEY").Value;
    var secret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));

    return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
}

现在,在我的 MVC 项目中,我有一个 Login 方法,该方法调用 API 进行登录并安全地保存令牌:

public async Task<IActionResult> Login(LoginViewModel model)
{
    // ... (omission for brevity)

    var token = await GetAccessToken(model); // call tha API to get the token

    if (!string.IsNullOrEmpty(token))
    {
        SaveToken(token);
        return RedirectToAction("Index", "Home");
    }
    else
    {
        ModelState.AddModelError("", "Invalid username or password");
    }
    return View(model);
} 
private void SaveTokenSecurely(string token)
{
    // Puoi salvare il token in un cookie sicuro, ad esempio:
    var cookieOptions = new CookieOptions
    {
        HttpOnly = true,
        Secure = true,
        SameSite = SameSiteMode.Strict,
        Expires = DateTime.UtcNow.AddHours(1)
    };

    Response.Cookies.Append("AccessToken", token, cookieOptions);
}

以下是我在 MVC 项目中配置身份验证的方法:

builder.Services.AddAuthentication(auth =>
{
    auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    auth.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
})
 .AddJwtBearer(options =>
 {
     var jwtSettings = builder.Configuration.GetSection("Jwt");
     var key = jwtSettings.GetSection("Key").Value;
     var issuer = jwtSettings.GetSection("Issuer").Value;

     options.TokenValidationParameters = new TokenValidationParameters
     {
         ValidateIssuer = true,
         ValidateAudience = false,
         ValidateLifetime = true,
         ValidateIssuerSigningKey = true,
         ValidIssuer = issuer,
         IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),

     };
 });

API 和 MVC 项目的 appsettings.json 文件相同:

  "Jwt": {
    "Issuer": "MY.PROJECT.Api",
    "lifetime": 15,
    "Key": "SUPERR STRONG KEY"
  }

问题是,尽管成功登录并获取了令牌,当我尝试使用 [Authorize(Roles = "Administrator")] 属性访问我的隐私页面时,我仍然收到 401 错误。我已验证“管理员”角色存在于我的令牌的有效负载中。

我在jwt.iohere is the result中检查了令牌。如果未选中

secret base64 encoded
,我会收到无效签名。

我还尝试从

Postman
调用 Privacy() 设置
Authorization
>
Bearer Token
>
and then the token
,这按预期工作。

我知道 Stack Overflow 上有几个关于 ASP.NET Core MVC 中 JWT 令牌未经授权的错误的问题,我已经研究了其中的一些问题:

有人知道问题可能是什么或者我如何解决它吗?预先感谢您的帮助!

临时解决方案

我解决了这个问题:

builder.Services.AddAuthentication(auth =>
{
    auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    auth.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
})
 .AddJwtBearer(options =>
 {
     var jwtSettings = builder.Configuration.GetSection("Jwt");
     var key = jwtSettings.GetSection("Key").Value;
     var issuer = jwtSettings.GetSection("Issuer").Value;

     options.TokenValidationParameters = new TokenValidationParameters
     {
         ValidateIssuer = true,
         ValidateAudience = false,
         ValidateLifetime = true,
         ValidateIssuerSigningKey = true,
         ValidIssuer = issuer,
         IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
     };
     options.Events = new JwtBearerEvents
     {
         OnMessageReceived = context =>
         {
             var token = context.Request.Cookies["AccessToken"];
             context.Token = token;
             return Task.CompletedTask;
         }
     };
 });

虽然这不是一个很好的解决方案。您能就我的问题提供完整的答案吗?

c# asp.net-core jwt asp.net-core-mvc bearer-token
1个回答
0
投票

我认为@DerDingens(在评论中)是正确的,总结一下:

  1. 如果 HTTP 请求不包含标头,这将永远不起作用:
'Authorization: Bearer <JWT_TOKEN>'

因为这就是 JWT 的工作原理:
'JWT auth' -> 表示 'Authorization: Bearer ...' 标头必须存在
如果您使用cookie,那么:
“Cookie”身份验证 -> Cookie 必须存在

  1. 在您的具体情况下(将 JWT 存储在 cookie 中): 我想我在互联网上多次看到类似的问题, 你可以用下面的代码解决这个问题。它与您的解决方案非常相似。

解决方案:在UseAuth..中间件之前添加设置标头“Authorization:Bearer”的中间件,例如:

// Add this middleware before authorization
// obviously 'AccessToken' is Your cookie name
app.Use(async (context, next) =>
{
    var token = context.Request.Cookies["AccessToken"];

    if (!string.IsNullOrEmpty(token) &&
        !context.Request.Headers.ContainsKey("Authorization"))
    {
        context.Request.Headers.Add("Authorization", "Bearer " + token);
    }

    await next();
});

我没有更好的想法,希望这能有所帮助。
问候
NeuroXiq

© www.soinside.com 2019 - 2024. All rights reserved.