Атрибут SignalR hub Authorize не работает
Я использую SignalR для отправки уведомлений в angular. Но я хочу сделать это для конкретного пользователя. Пользователь вошел в систему с помощью Azure Ad. И у меня есть [Авторизация] на хабе, но авторизация не удалась. Но в моем контроллере все работает нормально.
Что я пробовал до сих пор. Я попробовал эту услугу. AddAuthentication с сайта Microsoft. https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2 Но тогда мой контроллер не может проверить токен, потому что токен не находится в URL но в шапке.
startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
// Add custom configuration/resource files
services.ConfigureSettings(Configuration);
services.Configure<GzipCompressionProviderOptions>(options =>
options.Level = System.IO.Compression.CompressionLevel.Fastest
);
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins("http://localhost:4200"));
});
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAD", options));
services.AddSignalR();
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(new ValidateModelStateFilter());
}).AddJsonOptions(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
});
мой хаб:
[Authorize]
public class NotifyHub : Hub<ITypedHubClient>
{
public Task SendMessage(string user, string message)
{
return Clients.Client(Context.ConnectionId)
.BroadcastMessage("ReceiveMessage", user, message);
}
public Task Log(string email)
{
Debug.WriteLine(Context.ConnectionId);
return Clients.Caller.BroadcastMessage("succes", "string");
}
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
}
угловой сервис SignalR:
private createConnection() {
this._hubConnection = new HubConnectionBuilder()
.withUrl('https://localhost:44334/notify', { accessTokenFactory: () => {
return this.adalSvc.accessToken } })
.build();
}
Я хочу получить пользователя в своем хабе, чтобы я мог сопоставить пользователей с идентификаторами соединений.
3 ответа
Вы не показываете свой using
заявления, и я вижу, что вы также используете MVC. Может быть, вы используете неправильный AuthorizeAttribute?
Убедитесь, что вы используете Microsoft.AspNet.SignalR.AuthorizeAttribute
а не MVC один.
Проблема с SignalR заключается в том, что он не может изменить заголовок для отправки токена, поэтому
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAD", options));
не работает с SignalR, поскольку токен ожидается в URL-адресе.
Однако следующее работает как с аутентифицированными вызовами API, так и с аутентифицированными соединениями SignalR.
services.AddAuthentication(options = >{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options = >{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.Authority = "https://login.microsoftonline.com/" + Configuration["AzureAd:TenantId"];
options.TokenValidationParameters = new TokenValidationParameters() {
// These need to be set correctly after checking that it works
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false,
ValidateActor = false
};
options.Events = new JwtBearerEvents {
OnMessageReceived = ctx = >{
if (ctx.Request.Query.ContainsKey("access_token"))
ctx.Token = ctx.Request.Query["access_token"];
return Task.CompletedTask;
}
};
});
Вы можете проверить это в своем хабе
public override async Task OnConnectedAsync()
{
var Oid = (Context.User.FindFirst(c =>
c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
Debug.WriteLine(Oid);
}
Оба атрибута [Authorize] для API и SignalR взяты из
using Microsoft.AspNetCore.Authorization;
лучший способ использования авторизации для концентраторов - заставить приложение добавить токен jwt из строки запроса в контекст, и он работает для меня с помощью этого метода.
поместите это в свою программу.cs (точка сети 6):
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
o.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
if (string.IsNullOrEmpty(accessToken) == false)
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
и мои концентраторы такие, что используют основной метод авторизации asp
[Microsoft.AspNetCore.Authorization.Authorize]
public async Task myhub()
{
//do anything in your hub
}