使用 HttpOnly Cookie 身份验证的 ASP.NET Core 中 SignalR 连接的 CORS 预检失败

问题描述 投票:0回答:1

我正在开发一个带有 Vue.js 前端的 ASP.NET Core 应用程序,并且我正在尝试实现 SignalR 来实现实时通知。但是,我在尝试连接到我的 SignalR 集线器时遇到了 CORS 问题。以下是我的设置的详细信息以及我面临的错误。

项目设置

  • 前端:Vue.js,配置 withCredentials: true 来发送 cookie。
  • 后端:具有 JWT 身份验证的 ASP.NET Core,使用 HttpOnly cookie 来存储 JWT。

CORS 配置

            services.AddCors(options =>
            {
                string[] origins = [.. SecretsManager.GetSecret("Cors:AllowedOrigins").Split(',')];

                options.AddPolicy("AllowSpecificOrigins",
                    b => b.WithOrigins(origins)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials()
                );
            });

JWT 配置

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateIssuerSigningKey = true,
                    ValidateLifetime = true,
                    ValidIssuer = SecretsManager.GetSecret("Jwt:Issuer"),
                    ValidAudience = SecretsManager.GetSecret("Jwt:Audience"),
                    IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(SecretsManager.GetSecret("Jwt:Key"))
                    )
                };

                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = ctx =>
                    {
                        ctx.Request.Cookies.TryGetValue("access_token", out var accessToken);
                        if (!string.IsNullOrEmpty(accessToken))
                        {
                            ctx.Token = accessToken;
                        }

                        return Task.CompletedTask;
                    }
                };
            });

            services.AddAuthorization();

Vue.js 中的 SignalR 设置

    onMounted(() => {
    connection.value = new signalR.HubConnectionBuilder()
        .withUrl('http://localhost:5132/api/NotificationHub', {
            withCredentials: true
        })
        .build();

    connection.value.start()
        .then(() => console.log('SignalR Connected'))
        .catch(err => console.error('SignalR Connection Error: ', err));

NotificationHub.cs

    [HubEndpoint("api/NotificationHub")]
    [Authorize]
    public class NotificationHub : Hub
    {
        public override Task OnConnectedAsync()
        {
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            return base.OnDisconnectedAsync(exception);
        }
        public async Task SendMessage(string user, string message)
        {
            await Clients.Others.SendAsync("CreateMovie", user, message);
        }
    }

错误详情

    Access to fetch at 'http://localhost:5132/api/NotificationHub/negotiate?negotiateVersion=1' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The preflight OPTIONS request returns a 401 Unauthorized response with a WWW-Authenticate: Bearer header.

如果我删除授权属性,一切正常并建立连接 但是当我在集线器类上有 [Authorize] 属性时,它无法授权。 但即使失败,我仍然可以访问用户ID,例如在NotificationHub类的OnConnectedAsync中。

我无法从客户端传递 cookie,因为它是 httponly。

任何人都可以帮我找到在集线器上使用授权属性的解决方案吗?仅当用户获得授权时才建立连接?

谢谢

asp.net jwt signalr asp.net-core-webapi cookie-authentication
1个回答
0
投票

您应该使用

accessTokenFactory
而不是
withCredentials: true

官方文档配置承载身份验证

© www.soinside.com 2019 - 2024. All rights reserved.