【问题标题】:How do I add custom headers to SignalR's Typescript client?如何将自定义标头添加到 SignalR 的 Typescript 客户端?
【发布时间】:2020-01-08 18:58:09
【问题描述】:

我正在尝试在标头中传递不记名令牌以授权客户端连接。 SignalR 集线器通过从标头中获取不记名令牌来授权客户端。我无法修改 SingalR 集线器代码以使用查询字符串来获取令牌,也无法使用内置的 JWT 令牌功能。

如何向 SignalR 打字稿客户端添加自定义标头?

我唯一能想到的就是覆盖 HttpClient 以添加标头,但是我不确定这是否可行或如何做到这一点。

我在 Angular 8 和最新的@microsoft/signalr 包中使用@microsoft/signalr。

【问题讨论】:

  • 显示代码。

标签: c# angular typescript signalr


【解决方案1】:

您可以在建立连接时在选项中添加自定义的HttpClient。

看起来像这样:

class CustomHttpClient extends DefaultHttpClient {
  public send(request: HttpRequest): Promise<HttpResponse> {
    request.headers = { ...request.headers, "customHeader": "value" };
    return super.send(request);
  }
}

let hubConnection = new HubConnectionBuilder()
    .withUrl(url, { httpClient: new CustomHttpClient() })
    .build();

可以从DefaultHttpClient 继承,并在您的发送中调用 DefaultHttpClient 的发送,因此您不需要自己实现 Http 调用。

通过IHttpConnectionOptions 上的headers 属性在@microsoft/signalr 包的5.0 或更高版本中实现了一流的支持,有关已解决的GitHub 问题,请参阅https://github.com/dotnet/aspnetcore/issues/14588

【讨论】:

  • 需要注意的是,在使用 WebSockets 传输时设置标头将不起作用。我只对 JavaScript 客户端确定这一点,但我相信它将适用于所有 SignalR 客户端。
  • @Hedgybeats 是的,这是真的。要在 Javascript 客户端上设置标头,需要将传输类型显式提供为 LongPolling。它不适用于WebSocketsServerSentEvents
【解决方案2】:

如果这只是传递一个不记名令牌,那么不需要做自定义标头,传递一个访问令牌,你可以使用带有 IHttpConnectionOptions 的 withUrl 重载,这个接口有 accessTokenFactory 可以像这样使用:

yourAuthServicePromise.then(
  (data) => {
    if (data.['result']['accessToken']) {
      this.hubConnection = new signalR.HubConnectionBuilder()
        .withUrl('https://SIGNALR_SERVER_HUB_URL', {
          accessTokenFactory: () => {
            return data.['result']['accessToken'];
          }
        } as signalR.IHttpConnectionOptions)
        .build();
      this.hubConnection.start()
    }
  }
);

不要忘记在中心服务器中启用 cors 策略以允许 JS 客户端来源

【讨论】:

    【解决方案3】:

    我需要与@Brennan 的答案完全一样的东西。

    我刚刚填补了一些空白,以获得更多副本和可粘贴的答案。我正在使用它,它可以工作,谢谢@Brennan

    import * as signalR from "@aspnet/signalr";
    
    // You can create a factory which signalR will used to generate an access token on each request
    const getBearerToken = () => "MY TOKEN GETTING FUNCTION"
    
    // This is a custom method which creates all the headers I need for my authentication
    const getAuthHeaders = () => ({ collection: "", of: "", headers:""})
    
    // As per @Brennan's answer I used his advice and extened the default one
    class CustomHttpClient extends signalR.DefaultHttpClient {
      constructor() {
        super(console); // the base class wants an signalR.ILogger, I'm not sure if you're supposed to put *the console* into it, but I did and it seemed to work
      }
    
      // So far I have only overriden this method, and all seems to work well
      public async send(request: signalR.HttpRequest): Promise<signalR.HttpResponse> {
        var authHeaders = getAuthHeaders(); // These are the extra headers I needed to put in
        request.headers = { ...request.headers, ...authHeaders };
        // Now we have manipulated the request how we want we can just call the base class method
        return super.send(request);
      }
    }
    
     let connection = new signalR.HubConnectionBuilder()
        .withUrl(`${apiUrl}/web-sockets/stripeHub`, {
            accessTokenFactory: getBearerToken, // I also needed this, but you may not need it
            httpClient: new CustomHttpClient(), // This is the CustomClient we defined above which adds the headers to each request going out
         }) 
        .build();
    
    

    【讨论】:

      【解决方案4】:

      在创建集线器连接构建器时有一个名为headers 的选项。并且此选项仅在您使用 @microsoft/signalr npm 包时可用。这是 signalr 的活动仓库,旧的 (@aspnet/signalr) 已存档。

      所以有了新的 npm 包,你可以像下面那样做

      let connection = new signalR.HubConnectionBuilder()
      .withUrl("/chat", { 
       headers: { 
         "custom-header-name": "value" 
       },
       withCredentials: (true/false) // if you dont mention this value (if undefined by default it will set to true (which i didnt wanted in my case)
      })
      .build();
      

      注意:请记住,默认情况下自动重新连接是假的,所以添加withUrl().withAutomaticReconnect() 如果你愿意。

      更多关于options interface

      【讨论】:

      • 我试图传递 custum-header-name 这不起作用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 2013-09-24
      • 1970-01-01
      • 2011-05-02
      相关资源
      最近更新 更多