在我的客户端中,我使用这段代码来获取令牌,"http://localhost:5006" 是我的 IdentityServer(授权服务器)。
我的SignalR Hub是http://localhost:5119/Prevo100,当我运行StartAsync时,我遇到了以下异常:
System.AggregateException: '发生了一个或多个错误。(响应状态代码未指示成功:403(禁止)。)'
我也可能遇到401错误!
在SignalR服务器(hub)中,我使用以下代码:
我给hub类添加了一个属性。
var httpClient = new HttpClient();
var discoveryDocument = httpClient.GetDiscoveryDocumentAsync("http://localhost:5006").Result;
var tokenResponse = httpClient.RequestClientCredentialsTokenAsync(
new ClientCredentialsTokenRequest
{
Address = discoveryDocument.TokenEndpoint,
ClientId = "client",
ClientSecret = "Prevo100",
Scope = "prevo100-api"
}).Result;
我的SignalR Hub是http://localhost:5119/Prevo100,当我运行StartAsync时,我遇到了以下异常:
System.AggregateException: '发生了一个或多个错误。(响应状态代码未指示成功:403(禁止)。)'
我也可能遇到401错误!
var url = "http://localhost:5119/Prevo100";
HubConnection connection = new HubConnectionBuilder()
.WithUrl(url, options =>
{
options.AccessTokenProvider = () => Task.FromResult(tokenResponse.AccessToken);
})
.WithAutomaticReconnect()
.Build();
var client = new Prevo100WebClient(connection);
connection.StartAsync().Wait(); // <== Exception here
在SignalR服务器(hub)中,我使用以下代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:5006";
options.RequireHttpsMetadata = false;
options.Audience = "prevo100-api";
options.TokenValidationParameters =
new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateAudience = false
};
// 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.
// Sending the access token in the query string is required when using WebSockets or ServerSentEvents
// due to a limitation in Browser APIs. We restrict it to only calls to the
// SignalR hub in this code.
// See https://docs.microsoft.com/aspnet/core/signalr/security#access-token-logging
// for more information about security considerations when using
// the query string to transmit the access token.
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("/Prevo100"))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
services.AddSignalR(hubOptions =>
{
//hubOptions.ClientTimeoutInterval // 30 secondes par défaut
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<Prevo100Hub>("/Prevo100");
});
}
我给hub类添加了一个属性。
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class Prevo100Hub : Hub<IPrevo100Client>, IHubContract
{
//....
}