使用 Identity Server 4 失败的 SignalR 重音
Failed SignalR accentuations using Identity Server 4
我设置了 Identity Server 4、Asp.Net Core SignalR Hub 和 JavaScript 客户端。
当我尝试连接到 SignalR Hub 时,“negotiateVersion: 1”正确传递,但对集线器的请求根本没有传递。 Chrome 中的错误是“HTTP 身份验证失败;没有可用的有效凭据”和 FireFox 中的 401 状态代码。 id 和访问令牌存在于查询中。我尝试了不同的例子,但没有得到想要的结果。
版本:
身份服务器 4 - .Net 核心 2.1
- IdentityServer4.AspNetIdentity(2.5.0)
Asp.Net 核心 SignalR 中心 - .Net Core 3.1
- IdentityServer4.AccessTokenValidation(3.0.1)
- Microsoft.AspNetCore.Authentication.JwtBearer(3.1.7)
JavaScript 客户端
- signalr.min.js v4.2.2+97478eb6
这是我在 Identity Server 中的配置:
Config.cs
ClientId = "my.client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
Claims = { },
RedirectUris = {
"https://mySite/popupFrame.html",
"https://mySite/silentFrame.html",
},
PostLogoutRedirectUris = {"https://mySite/logoutFrame.html" },
RequireConsent = false,
AllowAccessTokensViaBrowser = true,
AccessTokenLifetime = (int)TimeSpan.FromMinutes(10).TotalSeconds,
Startup.cs 在 ConfigureServices 方法中
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>()
.AddResourceOwnerValidator<ResourceOwnerValidator>()
.AddProfileService<ProfileService>();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
这是我在 Asp.Net SignalR 中的配置:
Startup.cs 在 ConfigureServices 方法中
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44341";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
options.JwtBearerEvents = new JwtBearerEvents
{
OnMessageReceived = context =>
{
StringValues queryAccessToken = context.Request.Query["access_token"];
PathString path = context.HttpContext.Request.Path;
if (path.StartsWithSegments("/brokerhub") && !string.IsNullOrEmpty(queryAccessToken))
{
context.Token = queryAccessToken;
}
return Task.CompletedTask;
},
};
});
services.AddCors();
services.AddSignalR();
services.AddControllers();
配置方法中的Startup.cs
app.UseRouting();
app.UseCors(builder =>
{
builder.WithOrigins("https://mySite", "http://localhost")
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<BrokerHub>("/brokerhub", options =>
{
options.Transports = HttpTransportType.WebSockets;
});
});
集线器控制器
[Authorize]
public class BrokerHub : Hub
最后是 JS 客户端
client = new signalR.HubConnectionBuilder()
.withUrl('https://hub.com/brokerhub/', {
accessTokenFactory: () => {
return user.access_token;
}
})
.build();
任何人都可以指出我在配置中缺少的内容吗?
也许这个问题是相关的 - https://github.com/IdentityServer/IdentityServer4/issues/2349#issuecomment-394099795
能否请您尝试使用 options.TokenRetriever 而不是 OnMessageReceived ,如上文 link 所示,以及引入 CustomTokenRetriever?
我设置了 Identity Server 4、Asp.Net Core SignalR Hub 和 JavaScript 客户端。 当我尝试连接到 SignalR Hub 时,“negotiateVersion: 1”正确传递,但对集线器的请求根本没有传递。 Chrome 中的错误是“HTTP 身份验证失败;没有可用的有效凭据”和 FireFox 中的 401 状态代码。 id 和访问令牌存在于查询中。我尝试了不同的例子,但没有得到想要的结果。
版本: 身份服务器 4 - .Net 核心 2.1
- IdentityServer4.AspNetIdentity(2.5.0)
Asp.Net 核心 SignalR 中心 - .Net Core 3.1
- IdentityServer4.AccessTokenValidation(3.0.1)
- Microsoft.AspNetCore.Authentication.JwtBearer(3.1.7)
JavaScript 客户端
- signalr.min.js v4.2.2+97478eb6
这是我在 Identity Server 中的配置: Config.cs
ClientId = "my.client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
Claims = { },
RedirectUris = {
"https://mySite/popupFrame.html",
"https://mySite/silentFrame.html",
},
PostLogoutRedirectUris = {"https://mySite/logoutFrame.html" },
RequireConsent = false,
AllowAccessTokensViaBrowser = true,
AccessTokenLifetime = (int)TimeSpan.FromMinutes(10).TotalSeconds,
Startup.cs 在 ConfigureServices 方法中
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>()
.AddResourceOwnerValidator<ResourceOwnerValidator>()
.AddProfileService<ProfileService>();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
这是我在 Asp.Net SignalR 中的配置: Startup.cs 在 ConfigureServices 方法中
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44341";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
options.JwtBearerEvents = new JwtBearerEvents
{
OnMessageReceived = context =>
{
StringValues queryAccessToken = context.Request.Query["access_token"];
PathString path = context.HttpContext.Request.Path;
if (path.StartsWithSegments("/brokerhub") && !string.IsNullOrEmpty(queryAccessToken))
{
context.Token = queryAccessToken;
}
return Task.CompletedTask;
},
};
});
services.AddCors();
services.AddSignalR();
services.AddControllers();
配置方法中的Startup.cs
app.UseRouting();
app.UseCors(builder =>
{
builder.WithOrigins("https://mySite", "http://localhost")
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<BrokerHub>("/brokerhub", options =>
{
options.Transports = HttpTransportType.WebSockets;
});
});
集线器控制器
[Authorize]
public class BrokerHub : Hub
最后是 JS 客户端
client = new signalR.HubConnectionBuilder()
.withUrl('https://hub.com/brokerhub/', {
accessTokenFactory: () => {
return user.access_token;
}
})
.build();
任何人都可以指出我在配置中缺少的内容吗?
也许这个问题是相关的 - https://github.com/IdentityServer/IdentityServer4/issues/2349#issuecomment-394099795
能否请您尝试使用 options.TokenRetriever 而不是 OnMessageReceived ,如上文 link 所示,以及引入 CustomTokenRetriever?