2017-08-23 78 views
2

我试图使用ClaimsPrincipal登录,然后在.net core 2.0中获取JWT。随着我当前的代码,我得到的错误从SignInAsync函数的结果: “没有IAuthenticationSignInHandler被配置为处理登录的方案:承载”使用AuthenticateAsync生成JWT令牌

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

[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。然而,当我使用下面的代码JwtBearerDefaults.AuthenticationScheme我startup.cs:

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被配置为处理登录的方案:承载”

我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"; 
    } 

} 

回答

1

使用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); 
3

如果我理解正确的话,从找谁g在JwtBeaderHandler的源代码中,它没有实现IAuthenticationSignInHandler,这就是为什么你得到这个错误。对SignInAsync的调用旨在保存认证信息,例如创建的auth cookie,这正是CookieAuthenticationHandler的功能。但对于智威汤逊来说,没有一个知名的地方可以存储令牌,因此根本没有理由调用SignInAsync。取而代之的是,获取令牌并将其传递回浏览器。假设你正在重定向,你可以把它放到查询字符串中。假设浏览器应用程序是SPA(即基于Angular的),并且您需要用于AJAX调用的令牌,则应将令牌存储在SPA中,并将其与每个API请求一起发送。有一些关于如何使用JWT与不同类型的SPA的很好的教程,例如:https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f

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

+0

什么是需要从客户端发送令牌并将其传回?你知道如何实现IAuthenticationSignInHandler吗? –

+0

令牌仅在登录后立即从服务器传回给客户端。令牌包含已签名的用户身份。服务器是无状态的,因此浏览器客户端必须使用每个API调用将令牌发送到服务器,这意味着您的AJAX调用应该包含包含承载表示法的认证标头。 – iTolik

+1

用户输入名称/密码到您的客户端,它们被传递到服务器并进行验证。如果所有内容都检出,则会生成令牌(采用JWT格式,并由服务器签名,以便服务器稍后能够对其进行验证),并将其传回。客户端存储令牌并将其用于进一步的API调用。这就是流量。 它看起来在您的登录操作中已经生成JTW。这是完美的,因为现在你需要做的就是回报它。如果您正在进行重定向,您可以将其附加到查询字符串,或者您可以将它放在响应标题中,或者如果登录位于AJAX上,则将其作为JSON。 – iTolik