- 安装JWT,nuget:Microsoft.AspNetCore.Authentication.JwtBearer。
- 在 Program.cs 文件中signalr和JWT代码。
//跨域处理 builder.Services.AddCors(options => { options.AddPolicy("allowAllCors", builder => { builder .SetIsOriginAllowed(origin => true) //.AllowAnyOrigin() .AllowAnyHeader() .WithMethods(new string[] { "POST", "GET", "OPTIONS" }) .AllowCredentials(); }); }); //使用SignalR builder.Services.AddSignalR(); //配置JWT验证服务 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = true, ValidIssuer = "issuer", ValidateAudience = true, ValidAudience = "audience", ValidateLifetime = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretKey")) }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var path = context.HttpContext.Request.Path; //如果是signalr请求,需要将token转存,否则JWT获取不到token。OPTIONS请求需要过滤到,因为OPTIONS请求获取不到Token,用NGINX过滤掉OPTION请求. if (path.StartsWithSegments("/signalr")) { string accessToken = context.Request.Query["access_token"].ToString(); if (string.IsNullOrWhiteSpace(accessToken)) { accessToken = context.Request.Headers["Authorization"].ToString(); } context.Token = accessToken.Replace("Bearer ", "").Trim(); } return Task.CompletedTask; } }; }); //鉴权 app.UseAuthentication(); //授权 app.UseAuthorization(); //启用跨域配置 app.UseCors("allowAllCors"); //启用signalR app.MapHub<ServerHub>("/signalr").RequireCors("allowAllCors");
- ServerHub添加注解。
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [EnableCors("allowAllCors")] public class ServerHub : Hub{ }
- 使用NGINX做个代理,过滤掉OPTIONS方法,因为预检方法无法携带Token,这样会使JWT验证不通过,导致negotiate跨域问题的出现。
server { listen 8000; server_name 0.0.0.0; location /signalr { if ($request_method = 'OPTIONS') { access_log off; add_header Access-Control-Allow-Origin null; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Headers authorization,x-requested-with,x-signalr-user-agent; # 直接在这里返回204响应,不转发到后台服务程序 return 204; } proxy_pass http://x.x.x.x:5000/signalr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
- 前端代码:
this.socket_connection = new signalR.HubConnectionBuilder({ skipNegotiation: true, //针对webSocket为默认协议的时候,可以跳过协商 transport: signalR.HttpTransportType.WebSockets }).withUrl(this.url, { accessTokenFactory: () => "我的token" }).configureLogging(signalR.LogLevel.Error).build();
解决.net6中signalr使用JWT验证出现的negotiate跨域问题
最新推荐文章于 2024-06-01 22:55:42 发布