使用 AuthenticateAsync 生成 JWT 令牌
Generating a JWT token using AuthenticateAsync
我正在尝试使用 ClaimsPrincipal
登录,然后在 .net core 2.0 中获取 JWT。使用我当前的代码,我从 SignInAsync 函数的结果中得到错误:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: 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
函数的结果中得到错误:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"
我的令牌 class 是借助我在网上找到的代码(在 )创建的,定义如下:
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";
}
}
如果我通过查看 JwtBearerHandler 的源代码正确理解它,它不会实现 IAuthenticationSignInHandler,这就是您收到此错误的原因。调用 SignInAsync 旨在保留身份验证信息,例如创建的身份验证 cookie,这正是 CookieAuthenticationHandler 所做的。但对于 JWT 而言,没有单一的 well-known 位置来存储令牌,因此根本没有理由调用 SignInAsync。取而代之的是,获取令牌并将其传递回浏览器。假设您正在重定向,您可以将其放入查询字符串中。假设浏览器应用程序是一个 SPA(即 Angular-based)并且您需要用于 AJAX 调用的令牌,您应该将令牌存储在 SPA 中并在每个 API 请求中发送它。关于如何将 JWT 与不同类型的 SPA 一起使用,有一些很好的教程,例如:https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f
请记住,JwtBearerHandler 期望在其中找到带有 Bearer 的身份验证 header,因此如果您的 AJAX 调用将令牌放置在查询字符串中,您将需要提供 JwtBearerEvents.OnMessageReceived将从查询字符串中获取令牌并将其放入 header.
的实现
可以使用 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);
我正在尝试使用 ClaimsPrincipal
登录,然后在 .net core 2.0 中获取 JWT。使用我当前的代码,我从 SignInAsync 函数的结果中得到错误:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: 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
函数的结果中得到错误:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"
我的令牌 class 是借助我在网上找到的代码(在
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";
}
}
如果我通过查看 JwtBearerHandler 的源代码正确理解它,它不会实现 IAuthenticationSignInHandler,这就是您收到此错误的原因。调用 SignInAsync 旨在保留身份验证信息,例如创建的身份验证 cookie,这正是 CookieAuthenticationHandler 所做的。但对于 JWT 而言,没有单一的 well-known 位置来存储令牌,因此根本没有理由调用 SignInAsync。取而代之的是,获取令牌并将其传递回浏览器。假设您正在重定向,您可以将其放入查询字符串中。假设浏览器应用程序是一个 SPA(即 Angular-based)并且您需要用于 AJAX 调用的令牌,您应该将令牌存储在 SPA 中并在每个 API 请求中发送它。关于如何将 JWT 与不同类型的 SPA 一起使用,有一些很好的教程,例如:https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f
请记住,JwtBearerHandler 期望在其中找到带有 Bearer 的身份验证 header,因此如果您的 AJAX 调用将令牌放置在查询字符串中,您将需要提供 JwtBearerEvents.OnMessageReceived将从查询字符串中获取令牌并将其放入 header.
的实现可以使用 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);