我正在尝试使用SignalR为Blazor WASM应用程序实现身份验证例程,并基本上运行到墙上。
我已经启动并运行了一个外部Key斗篷服务器,WASM应用程序正在成功地对该服务器进行身份验证;客户端实际上得到了一个有效的JWT令牌等等。当我试图让SignalR Hub和客户端进行身份验证时,我遇到了问题。不过,只要我不将[Authenticate]
添加到集线器,就可以建立连接。
根据官方文档,这就是我应该让客户端连接到集线器的方式:
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/chathub"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(_accessToken);
})
.Build();
在SignalR集线器上,我应该这样做:
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
设置。
好吧,我终于找到了问题和解决方案。我对令牌验证默默失败的事实感到恼火,然后仔细查看了处理令牌的中间件。我注意到它基本上覆盖了一个事件处理程序,并问自己是否有其他事件处理程序?
好吧,你瞧,像这样添加OnAuthenticationFailed
并在返回中设置断点,让我看到了实际的错误消息:
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;
}
};
其声明CCD_ 8属性为空。我现在所要做的就是将正确的映射添加到我的Key斗篷服务器(请参阅这个StackOverflow线程(,并将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
{
[...]