【问题标题】:Error: Failed to complete negotiation with the server: Error : Status code '401'错误:无法完成与服务器的协商:错误:状态代码 \'401\'
【发布时间】:2023-01-14 18:06:47
【问题描述】:

在客户端使用 jwt 令牌成功登录后,我正在使用 SignalR 和 angular 在客户端之间创建聊天。一旦我添加了 -

[Authorize]

到我的集线器,我在尝试连接到 SignalR 时遇到此错误 -

调试:HubConnection 未能成功启动,因为错误“错误:无法完成与服务器的协商:错误::状态代码‘401’”。

在添加此属性之前,我的应用已成功连接到 SignalR,因此我知道问题出在授权上。我究竟做错了什么?

用户中心-

[Authorize]
public class UserHub : Hub

程序.cs-

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("CorsPolicy", builder => builder
        .WithOrigins("http://localhost:4200")
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials()
        .SetIsOriginAllowed((host) => true));
});

builder.Services.AddDbContext<TalkBackDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("TalkBackConnectionString")));

builder.Services.AddScoped<IContactRepository, ContactsRepository>();
builder.Services.AddScoped<IWebAPIService, WebAPIService>();
builder.Services.AddScoped<ISignalrService, SignalrService>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR(); 
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidAudience = builder.Configuration["Jwt:Audience"],
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
    };
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/user")))
            {
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        }
    };
});

客户-

public startSignalrConnection(connectionUrl: any) {
return new Promise<any>((resolve, reject) => {
  this.hubConnection = new HubConnectionBuilder()
    .withUrl(connectionUrl, { 
      withCredentials: false,
    accessTokenFactory: () => localStorage.getItem('jwt')!,
   })
    .configureLogging(LogLevel.Debug)
    .build();

【问题讨论】:

  • 在客户端代码中,您尝试在创建集线器连接时通过选项对象中的 accessTokenFactory 属性将 JWT 令牌传递给集线器连接。但是您没有传递 credentials 属性设置为 true 的令牌。在客户端创建集线器连接时,尝试将 { withCredentials: true, accessTokenFactory: () =&gt; localStorage.getItem('jwt')! } 添加到选项对象。这将以“Authorization: Bearer {token}”格式在请求标头中发送 JWT 令牌,服务器将能够读取令牌并授权连接。
  • 我已将其更改为“真”,但仍然出现相同的错误:“建立信号器连接时出错:错误:无法完成与服务器的协商:错误::状态代码为‘401’”。有任何想法吗?
  • 您在哪里将任何类型的身份验证信息添加到您的 http 调用中?像 auth 拦截器或类似的。
  • 如果我没理解错的话,我在网上看到 accessTokenFactory: () =&gt; localStorage.getItem('jwt')! 应该就足够了
  • 您是否将任何类型的 jwt 信息保存到本地存储中?

标签: asp.net angular authentication jwt signalr


【解决方案1】:

经过多次尝试,我发现了问题所在。 我错过了 Program.cs 上的这一行 -

app.UseAuthentication();

我还编辑了我的令牌(在另一个微服务上)与此处相同,并添加了这一行 -

ValidateIssuerSigningKey=true

现在我可以访问 SignalR。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-18
    • 2020-07-04
    • 2017-07-06
    • 1970-01-01
    相关资源
    最近更新 更多