Авторизация не работает в Signalr ASP.NET Core 2.1
Я обновил свой проект с ASP.Net Core 2.0 до ASP.NET Core 2.1, следуя этому руководству.
Все было хорошо, пока я не применил Signar Core 2.1 к своему проекту.
Это мое Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IAuthorizationHandler, SolidAccountRequirementHandler>();
services.AddCors(
options => options.AddPolicy("AllowCors",
builder =>
{
builder
.AllowAnyOrigin()
.AllowCredentials()
.AllowAnyHeader()
.AllowAnyMethod();
})
);
services.AddAuthorization(x =>
{
x.AddPolicy("MainPolicy", builder =>
{
builder.Requirements.Add(new SolidAccountRequirement());
});
});
services.AddSignalR();
#region Mvc builder
var authenticationBuilder = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);
authenticationBuilder.AddJwtBearer(o =>
{
// You also need to update /wwwroot/app/scripts/app.js
o.SecurityTokenValidators.Clear();
// Initialize token validation parameters.
var tokenValidationParameters = new TokenValidationParameters();
tokenValidationParameters.ValidAudience = "audience";
tokenValidationParameters.ValidIssuer = "issuer";
tokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SigningKey"));
tokenValidationParameters.ValidateLifetime = false;
o.TokenValidationParameters = tokenValidationParameters;
});
// Construct mvc options.
services.AddMvc(mvcOptions =>
{
////only allow authenticated users
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.AddRequirements(new SolidAccountRequirement())
.Build();
mvcOptions.Filters.Add(new AuthorizeFilter(policy));
})
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1); ;
#endregion
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseCors("AllowCors");
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/chathub");
});
app.UseMvc();
}
}
Это мое SolidRequirementHandler
public class SolidAccountRequirementHandler : AuthorizationHandler<SolidAccountRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SolidAccountRequirement requirement)
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
Это мое ChatHub.cs
:
public class ChatHub : Hub
{
[Authorize(Policy = "MainPolicy")]
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
}
То, что я ожидал, было MainPolicy
будет вызван, когда я использовал мое приложение AngularJS для подключения к ChatHub
, Тем не мение, OnConnectedAsync()
Функция была вызвана без проверки личности запроса.
Политика MVC Controller была успешно применена, а Signalr - нет.
Кто-нибудь может мне помочь?
Спасибо,
1 ответ
Я разместил этот вопрос на странице выпуска Signalr github. Вот ответ, который они дали мне. Я пытался, и это сработало успешно:
Решение состоит в том, чтобы поставить [Authorize]
приписать ChatHub
[Authorize(Policy = "MainPolicy")]
public class ChatHub : Hub
{
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
}
Просто поделись тем, кто не знает:)
У меня такая же проблема, есть четыре ключевых момента:
1- В вашем Startup.cs помните об этом порядке внутри
Configure(IApplicationBuilder app)
app.UseRouting();
app.UseAuthorization( );
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<myChat>("/chat");
});
то
app.UseAuthorization( );
всегда должно быть между
app.UseRouting();
и
app.UseEndpoints()
.
2- SignalR не отправляет токены в заголовке, а отправляет их в запросе. В вашем startup.cs внутри
ConfigureServices(IServiceCollection services)
Вы должны настроить свое приложение таким образом, чтобы оно считывало токены из запроса и помещало их в заголовок. Вы можете настроить свой JWT следующим образом:
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidIssuer = [Issuer Site],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes([YOUR SECRET KEY STRING]))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var path = context.Request.Path;
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/chat"))
{
context.Request.Headers.Add("Authorization", new[] { $"Bearer {accessToken}" });
}
return Task.CompletedTask;
}
};
});
3- Ваш клиент должен отправить токен, когда он хочет установить соединение. Вы можете добавить токен в Query при создании соединения.
var connection = new signalR.HubConnectionBuilder().withUrl(
"http://localhost:5000/chat", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets,
accessTokenFactory: () => "My Token Is Here"}).build();
4- Я не добавил схему аттестации по умолчанию внутри
services.AddAuthentication()
Поэтому каждый раз мне приходится указывать свою схему авторизации вот так.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
И, наконец, вы можете защитить свой класс чата вот так
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class myChat : Hub
{
///Some functions
}
Кажется, что использование операторов важно, поэтому убедитесь, что используете правильные. Атрибут авторизации концентратора SignalR не работает
Примечание. У меня проблема с авторизацией только одного метода в
myChat
класс. Не знаю почему.