JWT + SignalR on ASP Core 3 resulting in 401 Unauthorized
如果我在Signalr之外使用http调用(例如与邮递员或httpclient一起使用),则可以在服务器上成功验证我的令牌。当我尝试通过信号中心进行连接时,令牌未通过授权。
Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token: Bearer MyTokenFooBar
我的服务设置是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public void ConfigureServices(IServiceCollection services) { services.AddRouting(); services.AddControllers(); services.AddHealthChecks(); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder => { builder.ConnectionString = _configuration.GetConnectionString("DefaultConnection"); })); services.AddIdentity<ApplicationUser, IdentityRole>(setup => { // foo }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.SaveToken = true; options.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = _configuration["Jwt:Issuer"], ValidAudience = _configuration["Jwt:Audience"], ValidateIssuer = false, ValidateAudience = false, ValidateIssuerSigningKey = false, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"])), ValidateLifetime = false }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var path = context.HttpContext.Request.Path; if (!path.StartsWithSegments("/chat")) return Task.CompletedTask; var accessToken = context.Request.Headers[HeaderNames.Authorization]; if (!string.IsNullOrWhiteSpace(accessToken) && context.Scheme.Name == JwtBearerDefaults.AuthenticationScheme) { context.Token = accessToken; } return Task.CompletedTask; } }; }); services.AddAuthorization(); services.AddSignalR(options => { options.EnableDetailedErrors = true; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(options => { options.MapHealthChecks("/health"); options.MapControllerRoute("default","{controller=Home}/{action=Index}/{id?}"); }); app.UseSignalR(options => { options.MapHub<ChatHub>("/chat"); }); } |
我为初始连接使用基本的http auth标头,该标头将使用户签名并生成jwt令牌作为响应,以供将来的调用中使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [HttpPost] [AllowAnonymous] public async Task<IActionResult> Login() { var (headerUserName, headerPassword) = GetAuthLoginInformation(HttpContext); var signInResult = await _signInManager.PasswordSignInAsync(headerUserName, headerPassword, false, false); if (!signInResult.Succeeded) { return Unauthorized(); } var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SuperTopSecretKeyThatYouDoNotGiveOutEver!")); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); var jwt = new JwtSecurityToken(signingCredentials: signingCredentials); var handler = new JwtSecurityTokenHandler(); var token = handler.WriteToken(jwt); return new OkObjectResult(token); } |
然后将我的客户端(控制台应用程序)设置为缓存此令牌,并在以后的信号发出者调用中使用它,例如:
获取令牌:
1 2 3 | _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(encoding.GetBytes($"{userName}:{password}"))); var response = await _client.SendAsync(request); // this goes to the login action posted above _token = await response.Content.ReadAsStringAsync(); |
...
1 2 3 4 5 6 7 | _hubConnection = new HubConnectionBuilder() .WithUrl(new Uri(_baseAddress,"chat"), options => { options.AccessTokenProvider = () => Task.FromResult(_token); }) // send the cached token back with every request .Build(); // here is where the error occurs. 401 unauthorized comes back from this call. await _hubConnection.StartAsync(); |
已解决。
问题是我覆盖了
只需删除我对