【问题标题】:Generating a JWT token using AuthenticateAsync使用 AuthenticateAsync 生成 JWT 令牌
【发布时间】:2018-02-01 14:06:52
【问题描述】:

我正在尝试使用 ClaimsPrincipal 登录,然后在 .net core 2.0 中获取 JWT。使用我当前的代码,我从 SignInAsync 函数的结果中得到错误: "没有配置 IAuthenticationSignInHandler 来处理方案的登录:Bearer"

这是我目前使用的控制器:

[Route("Login/{username}")]
public async Task<IActionResult> Login(string username)
{
    var userClaims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, username)
    };
    var principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
    var sign = HttpContext.SignInAsync(principal);
    await sign;
    var res = await HttpContext.AuthenticateAsync();
    var token = await HttpContext.GetTokenAsync("access_token");
    return Json(token);
}

登录部分已经过测试,可以很好地与 cookie 配合使用。但是,当我在 startup.cs 中使用以下代码和 JwtBearerDefaults.AuthenticationScheme 时:

services.AddAuthentication(config => {
    config.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    config.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(config =>
{
    config.TokenValidationParameters = Token.tokenValidationParameters;
    config.RequireHttpsMetadata = false;
    config.SaveToken = true;
});

我从SignInAsync 函数的结果中得到错误: "没有配置 IAuthenticationSignInHandler 来处理方案的登录:Bearer"

我的 Token 类是在我在网上(JWT on .NET Core 2.0)找到的代码的帮助下创建的,定义如下:

public static class Token
{

    public static TokenValidationParameters tokenValidationParameters {
        get
        {

            return new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = GetSignInKey(),
                ValidateIssuer = true,
                ValidIssuer = GetIssuer(),
                ValidateAudience = true,
                ValidAudience = GetAudience(),
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
        }
    }

    static private SymmetricSecurityKey GetSignInKey()
    {
        const string secretKey = "very_long_very_secret_secret";
        var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));

        return signingKey;
    }

    static private string GetIssuer()
    {
        return "issuer";
    }

    static private string GetAudience()
    {
        return "audience";
    }

}

【问题讨论】:

    标签: jwt claims-based-identity claims .net-core-2.0


    【解决方案1】:

    如果我通过查看 JwtBearerHandler 的源代码理解正确,它没有实现 IAuthenticationSignInHandler,这就是您收到此错误的原因。调用 SignInAsync 旨在持久保存身份验证信息,例如创建的身份验证 cookie,例如,这正是 CookieAuthenticationHandler 所做的。但是对于 JWT 来说,没有一个众所周知的地方可以存储令牌,因此根本没有理由调用 SignInAsync。取而代之的是,获取令牌并将其传递回浏览器。假设您正在重定向,您可以将其放入查询字符串中。假设浏览器应用程序是一个 SPA(即基于 Angular)并且您需要用于 AJAX 调用的令牌,您应该将令牌存储在 SPA 中并与每个 API 请求一起发送。关于如何将 JWT 与不同类型的 SPA 一起使用,有一些很好的教程,例如:https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f

    请记住,JwtBearerHandler 期望在其中找到带有 Bearer 的 Authentication 标头,因此,如果您的 AJAX 调用将令牌放入查询字符串中,您将需要提供 JwtBearerEvents.OnMessageReceived 实现,该实现将从查询字符串中获取令牌并将其放入标题。

    【讨论】:

    • 需要从客户端发送令牌并将其传回吗?你知道如何实现 IAuthenticationSignInHandler 吗?
    • 令牌仅在登录后立即从服务器传回客户端一次。令牌包含签名的用户身份。服务器是无状态的,因此浏览器客户端必须在每次 API 调用时向服务器发送令牌,这意味着您的 AJAX 调用应包含包含 Bearer 表示法的 Authentication 标头。
    • 用户在您的客户端中输入名称/密码,然后将它们传递给服务器并进行验证。如果所有内容都检查完毕,则会生成令牌(JWT 格式,并且由服务器签名,因此服务器稍后将能够对其进行验证)并发送回。客户端存储令牌并在进一步的 API 调用中使用它。这就是流量。看起来在您的登录操作中您已经在生成 JTW。这是完美的,因为现在您需要做的就是归还它。如果您正在执行重定向,您可以将其附加到查询字符串,或者您可以将其放在响应标头中,或者如果登录是在 AJAX 上,则作为 JSON。
    • 无论如何,我认为您根本不需要为此实现 IAuthenticationSignInHandler。
    • 我知道流程是如何工作的。我曾多次在客户端使用令牌。事实上,我主要是在寻找一种在服务器中生成令牌的方法。上面的方法并没有真正奏效。我仍然不知道HttpContext.GetTokenAsync 究竟做了什么。
    【解决方案2】:

    可以使用JwtSecurityTokenHandler 创建签名令牌。

    var handler = new JwtSecurityTokenHandler();
    var jwt = handler.CreateJwtSecurityToken(new SecurityTokenDescriptor
    {
         Expires = DateTime.UtcNow.Add(Expiary),
         Subject = new ClaimsIdentity(claims, "local"),
         SigningCredentials = new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256)
    });
    return handler.WriteToken(jwt);
    

    【讨论】:

      猜你喜欢
      • 2018-08-29
      • 2021-07-29
      • 2017-04-06
      • 2020-09-28
      • 1970-01-01
      • 2021-05-31
      • 2022-01-14
      • 2017-11-01
      相关资源
      最近更新 更多