【问题标题】:403 (Forbidden) response from SignalR Hub using ASP.NET hosting on IIS server使用 IIS 服务器上的 ASP.NET 托管来自 SignalR Hub 的 403(禁止)响应
【发布时间】:2019-03-13 14:13:58
【问题描述】:

我在 Windows Server 2012 上托管一个 SignalR 集线器,将 IIS 作为 ASP.NET Web 应用程序,我已在本地计算机上成功测试过该应用程序。但是,当我发布并尝试从 Angular 应用程序连接时,服务器会在 /negotiate 请求上响应 403 Forbidden。 Angular 应用程序与 Hub 服务器位于不同的域中。

我了解到这是由 CORS 问题引起的,但我已经尝试了所有可以找到的解决方案,但没有进行任何更改。可能是 IIS 服务器问题还是我的代码中遗漏了什么?

被调用的路由是https://example.com/signalr/negotiate

SignalR 服务器:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Map("/signalr", map =>
        {
            map.UseCors(CorsOptions.AllowAll);

            var hubConfiguration = new HubConfiguration
            {
                EnableJSONP = true,
                EnableDetailedErrors = true
            };

            map.RunSignalR(hubConfiguration);
        });
    }
}

// Hub that handles Online user list
public class OnlineHub : Hub
{
    private static List<AppUserDto> _usersOnline = new List<AppUserDto>();

    public OnlineHub()
    {
        // Automapper Setup
        MappingConfig.Init();
    }

    public override Task OnConnected()
    {
        var user = GetUser();
        _usersOnline.Add(user);
        Clients.All.listUpdated(_usersOnline);

        return base.OnConnected();
    }

    public override Task OnReconnected()
    {
        var user = GetUser();

        // Add user to list of online users if it doesn't exist
        if (!_usersOnline.Any(u => u.Email == user.Email))
        {
            _usersOnline.Add(user);
            Clients.All.listUpdated(_usersOnline);
        }

        return base.OnReconnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        var user = GetUser();
        if (!_usersOnline.Any(u => u.Email == user.Email))
        {
            // Remove user from list of online users
            _usersOnline.Remove(user);

            Clients.All.listUpdated(_usersOnline);
        }

        return base.OnDisconnected(stopCalled);
    }

    private AppUserDto GetUser()
    {
        using (var db = new EntityDbContext())
        {
            // Get connected AppUserDto
            var user = db.AppUsers.FirstOrDefault(u => u.UserName == Context.User.Identity.Name);
            // Add user to list of online users
            if (user != null)
            {
                return Mapper.Map<AppUserDto>(user);
            }

            return null;
        }
    }
}

Angular 应用程序 SignalR 服务

import { AppSettings } from './../app.settings';
import { EventEmitter, Injectable } from '@angular/core';

declare const $: any;

@Injectable()
export class SignalRService {
  // Declare the variables
  private proxy: any;
  private connection: any;
  private authData: any;
  // create the Event Emitter
  public messageReceived: EventEmitter<any>;
  public connectionEstablished: EventEmitter<Boolean>;
  public connectionExists: Boolean;

  constructor(private appSettings: AppSettings) {
    // Setup
    this.connectionEstablished = new EventEmitter<Boolean>();
    this.messageReceived = new EventEmitter<any>();
    this.connectionExists = false;
  }

  public initialize(proxyName: string): void {
    this.connection = $.hubConnection(this.appSettings.SIGNALR_BASE_URL);
    this.proxy = this.connection.createHubProxy(proxyName);
    this.registerOnServerEvents();
    this.startConnection();
  }

  private startConnection(): void {
    this.connection.start({withCredentials: false})
      .done((data: any) => {
        console.log('SignalR Connected with: ' + data.transport.name);
        this.connectionEstablished.emit(true);
        this.connectionExists = true;
      })
      .fail((error: any) => {
        console.log('SignalR could not connect: ' + error);
        this.connectionEstablished.emit(false);
      });
  }

  private registerOnServerEvents() {
    this.proxy.on('listUpdated', (list: any) => {
      console.log(list);
      this.messageReceived.emit(list);
    });
  }
}

initialize(proxyName) 从控制器调用以启动与 Hub 的连接。

更新

我尝试使用 .NET Core 2.0 重建服务器和集线器,但是当我在 IIS 服务器上进行测试时,我得到:

“加载 https://signalr.example.com/online/negotiate 失败:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。来源“https://example.com”因此不允许访问。”

因此,即使我已经像多个指南一样设置了所有内容,这仍然是一个 CORS 问题。

【问题讨论】:

    标签: javascript c# asp.net angular signalr


    【解决方案1】:

    过去我遇到过问题,您尝试访问的 api 路径实际上是一个虚拟目录,然后 IIS 会返回一个 403,因为它认为您正在尝试查看/访问该目录而不是webAPI 路由。

    如果您的服务器上有目录api/negotiateGET api/negotiate403

    如果您的 WebApiController 位于您的项目中的以下目录中,就会出现这种情况:

    /api/negotiate/NegotiateApiController.cs
    

    如果是这种情况,您可以通过更改路由或目录名称轻松解决此问题。

    注意:这将在某些浏览器上以 405 的形式返回。

    【讨论】:

    • 我使用的项目不是WebApi项目,我只有OnlineHub.cs和Startup.cs这两个文件。我已经仔细检查了服务器,恐怕没有与该路由对应的目录。被调用的网址是example.com/signalr/negotiate?...
    • 我注意到,如果我尝试从运行应用程序的服务器访问该 URL,我会返回 405。但远程我得到 403。
    猜你喜欢
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 2023-04-06
    • 2014-02-06
    相关资源
    最近更新 更多