我有一个REST API(核心2.1),该API需要支持SPA,并使用SignalR提供宁静的端点和一些实时交互功能;
集线器/ MVC路由在同一服务器上运行,该服务器也是JWT令牌的提供者。
登录后,客户端会收到一个JWT令牌,该令牌将在每个REST请求的标头上放置,否则它将获得401(这与[Authorize]
属性一起使用)。
在客户端,下面的代码尝试连接到我的/ hub端点:
new HubConnectionBuilder().withUrl(HUB_URL, { accessTokenFactory: () => this.getToken() })
并且,如果将[Authorize]
放在Hub类中,则会出现以下错误(没有授权,客户端可以正确发送和收听):
与'wss:// localhost:5001 / hub?id = MY_ID&access_token = MY_TOKEN'的WebSocket连接失败:HTTP身份验证失败;没有有效的凭据
服务器记录了失败的身份验证:
(在AddJwtBearerOptions.Events.OnMessageReceived上触发了console.log)
信息:Microsoft.AspNetCore.Hosting.Internal.WebHost [1]
请求启动HTTP / 1.1 GET https://localhost:5001/hub? id = MY_ID&access_token = MY_TOKEN
信息:Microsoft.AspNetCore.Authorization.DefaultAuthorizationService [2]
授权失败。
信息:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [12]
AuthenticationScheme:承载受到了挑战。
信息:Microsoft.AspNetCore.Hosting.Internal.WebHost [2]
请求在0.3658毫秒内完成401
与那些请求不同,将SAME JWT TOKEN与REST请求一起使用(使用[Authorize]
),并与Header: Bearer XXXX
而不是querystring一起触发OnTokenValidated
。即使验证失败,也不会触发OnAuthenticationFailed
:
(在AddJwtBearerOptions.Events.OnMessageReceived上触发了console.log)
信息:Microsoft.AspNetCore.Hosting.Internal.WebHost [1]
请求启动HTTP / 1.1 GET https://localhost:5001/api/products application / json
(在AddJwtBearerOptions.Events.OnTokenValidated上触发了console.log)
信息:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [2]
成功验证令牌。
ConfigureServices(IServiceCollection)
services.AddSignalR();
services.AddCors(option => option.AddPolicy("CorsPolicy", p => p.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod().AllowCredentials()));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters{
ValidateIssuer = true,
ValidIssuer = Configuration["JWT:Issuer"],
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:SecurityKey"]))
};
});
Configure(IApplicationBuilder)
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseHttpsRedirection();
app.UseMvc();
app.UseSignalR(routes => {
routes.MapHub<ApplicationHub>("/hub");
});
答案 0 :(得分:1)
您还需要将此块添加到.AddJwtBearer
部分中:
// We have to hook the OnMessageReceived event in order to
// allow the JWT authentication handler to read the access
// token from the query string when a WebSocket or
// Server-Sent Events request comes in.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
这可以在the docs中找到。
答案 1 :(得分:0)
信息:Microsoft.AspNetCore.Authorization.DefaultAuthorizationService [2] 授权失败。 信息:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [12] AuthenticationScheme:承载受到了挑战。 信息:Microsoft.AspNetCore.Hosting.Internal.WebHost [2] 请求已在0.3658毫秒内完成401
花费20个小时进行修复。 :( 原因在:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class ChatHub : Hub<IChatClient>
我的服务配置:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => ...)
UPD: JS客户端here的完整工作示例。