JWT验证因SignalR而失败

时间:2018-10-13 20:35:19

标签: c# asp.net-core signalr jwt

我有一个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]
        成功验证令牌。


在我的“ Startup.cs”下面检查

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

2 个答案:

答案 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的完整工作示例。