Blazor WebAssembly SignalR 身份验证在协商时未通过 AccessToken
Blazor WebAssembly SignalR authentication not passing AccessToken upon negotiation
我正在尝试使用 SignalR 为 Blazor WASM 应用程序实施身份验证例程,并且 运行 基本上是在墙上。
我已经启动了一个外部 Keycloak 服务器并且 运行ning 并且 WASM 应用程序成功地通过了那个服务器的身份验证;客户端实际上获得了一个有效的 JWT 令牌和所有。当我尝试让 SignalR Hub 和客户端验证我 运行 遇到问题时。不过,只要我不将 [Authenticate]
添加到集线器,就会建立连接。
根据官方文档,这就是我应该让客户端连接到集线器的方式:
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/chathub"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(_accessToken);
})
.Build();
在 SignalR Hub 上我应该这样做:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://keycloak/auth/realms/master/";
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("/chathub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
我在客户端得到的只是控制台上的一个错误,带有一个大 401
(即“未授权”)
我能够向应用程序添加自定义授权例程(每次身份验证尝试都返回“成功”)并找出问题的可能根源:
客户端对集线器进行 两次 连接尝试。第一个是/chathub/negotiate?negotiateVersion=1
,第二个是/chathub
.
但是,只有第二个请求携带了access_token!结果,使用上面的代码将在第一步中断,因为 access_token 似乎在谈判阶段已经需要 HubConnectionBuilder
由于某种原因不提供该参数。
我做错了什么?
编辑:请参阅下面的答案。问题不是缺少令牌,而是缺少 options.Audience
设置。
好的,我终于找到了问题和解决方案。我对令牌验证无声地失败这一事实感到恼火,然后仔细研究了处理令牌的中间件。
我注意到它基本上覆盖了一个事件处理程序并问自己是否有 other 个事件处理程序?
好吧,你瞧,像这样添加 OnAuthenticationFailed
并在 return 上设置断点让我看到了实际的错误消息:
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("/chathub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
}
};
表示 Audience
属性 为空。我现在所要做的就是将正确的映射添加到我的 Keycloak 服务器(请参阅此 线程)并将 options.Audience = "ClientId"
添加到配置中,如下所示:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://keycloak/auth/realms/master";
options.Audience = "ClientID";
options.Events = new JwtBearerEvents
{
[...]
我正在尝试使用 SignalR 为 Blazor WASM 应用程序实施身份验证例程,并且 运行 基本上是在墙上。
我已经启动了一个外部 Keycloak 服务器并且 运行ning 并且 WASM 应用程序成功地通过了那个服务器的身份验证;客户端实际上获得了一个有效的 JWT 令牌和所有。当我尝试让 SignalR Hub 和客户端验证我 运行 遇到问题时。不过,只要我不将 [Authenticate]
添加到集线器,就会建立连接。
根据官方文档,这就是我应该让客户端连接到集线器的方式:
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/chathub"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(_accessToken);
})
.Build();
在 SignalR Hub 上我应该这样做:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://keycloak/auth/realms/master/";
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("/chathub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
我在客户端得到的只是控制台上的一个错误,带有一个大 401
(即“未授权”)
我能够向应用程序添加自定义授权例程(每次身份验证尝试都返回“成功”)并找出问题的可能根源:
客户端对集线器进行 两次 连接尝试。第一个是/chathub/negotiate?negotiateVersion=1
,第二个是/chathub
.
但是,只有第二个请求携带了access_token!结果,使用上面的代码将在第一步中断,因为 access_token 似乎在谈判阶段已经需要 HubConnectionBuilder
由于某种原因不提供该参数。
我做错了什么?
编辑:请参阅下面的答案。问题不是缺少令牌,而是缺少 options.Audience
设置。
好的,我终于找到了问题和解决方案。我对令牌验证无声地失败这一事实感到恼火,然后仔细研究了处理令牌的中间件。 我注意到它基本上覆盖了一个事件处理程序并问自己是否有 other 个事件处理程序?
好吧,你瞧,像这样添加 OnAuthenticationFailed
并在 return 上设置断点让我看到了实际的错误消息:
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("/chathub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
}
};
表示 Audience
属性 为空。我现在所要做的就是将正确的映射添加到我的 Keycloak 服务器(请参阅此 options.Audience = "ClientId"
添加到配置中,如下所示:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://keycloak/auth/realms/master";
options.Audience = "ClientID";
options.Events = new JwtBearerEvents
{
[...]