首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >由于401,SignalR连接返回到长轮询。

由于401,SignalR连接返回到长轮询。
EN

Stack Overflow用户
提问于 2022-11-09 14:46:08
回答 1查看 49关注 0票数 0

我有一个带有角13后端的.net 6后端,它使用JWT令牌作为auth。出于某种原因,localhost:PORT/hubs/myhub?id=ID&access_token=JWTTOKEN总是回到长轮询,无论是在prod上还是在dev机器上,对negotiate?negotiateVersion=1的调用似乎都是成功的,它选择了WebSockets,但之后对negotiate?negotiateVersion=1的调用返回了401。

角度部分使用NGRX获取JWT令牌,JWT令牌在5分钟后过期。当它在连接建立后接收到401时,它断开连接,进行正常的更新调用,并再次与新的JWT令牌连接。然而,即使使用有效的令牌,上面描述的请求也总是返回401。

我的SignalR服务:

代码语言:javascript
复制
export class NotificationSignalrService {

  private connection: signalR.HubConnection;
  connectionClosedRefreshTokenSubscription: Subscription | undefined;
  startConnectionRefreshTokenSubscription: Subscription | undefined;

  constructor(@Inject(APP_CONFIG) private appConfig: any, private store: Store) {
    this.connection = new signalR.HubConnectionBuilder()
      .withUrl(`${this.appConfig.SIGNALR}/hubs/notificationhub`, this.hubConnectionOptions)
      .configureLogging(signalR.LogLevel.Debug)
      //.withAutomaticReconnect()
      .build();

    this.connection.onclose(error => {
      console.log(`Forbindelse lukket pga: ${error}`);
      this.store.dispatch(AuthActions.renewNoLoading());
      this.connectionClosedRefreshTokenSubscription = this.store.select(AuthSelectors.selectTokenRefreshed).subscribe({
        next: tokenRefreshed => {
          if (tokenRefreshed) {
            this.connectionClosedRefreshTokenSubscription?.unsubscribe();

            this.startSignalRConnection();
          }
        }
      })
    });


    this.startSignalRConnection();
    this.startListening();
  }

  startSignalRConnection() {
    this.connection.start().catch(error => {
      console.log(`Der skete en fejl ved start af signalR ${error}`);
      this.startConnectionRefreshTokenSubscription = this.store.select(AuthSelectors.selectTokenRefreshed).subscribe({
        next: tokenRefreshed => {
          if (tokenRefreshed) {
            this.startConnectionRefreshTokenSubscription?.unsubscribe();
            this.connection.start().catch(error => console.log(`Kunne ikke starte forbindelsen efter renew ${error}`));
          }
        }
      })
    });

  }

  @HostListener('window:beforeunload', ['$event'])
  beforeunloadHandler() {
    this.connection.stop();
  }

  protected get hubConnectionOptions(): IHttpConnectionOptions {
    // NOTE: The auth token must be updated for each request. So using headers option is not true.
    //       Also for websockets and some other protocols signalr cannot set auth headers.
    //       See https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-5.0#bearer-token-authentication

    return {
      /*headers,*/
      accessTokenFactory: () => {
        return this.store.select(AuthSelectors.getLoggedInToken)
          .pipe(take(1), filter(x => x !== null), map(x => x === null ? "" : x)).toPromise();

        // this.authService.refreshLogin()
        //   .pipe(map(_ => this.authService.accessToken)).toPromise();
      }
    };

    // NOTE:
    // The access token function you provide is called before every HTTP request made by SignalR. If you need to renew the token in order to keep the connection active (because it may expire during the connection), do so from within this function and return the updated token.
    // In standard web APIs, bearer tokens are sent in an HTTP header. However, SignalR is unable to set these headers in browsers when using some transports. When using WebSockets and Server - Sent Events, the token is transmitted as a query string parameter.
  }
  getAuthToken() {
    let token = '';
    this.store.select(AuthSelectors.getLoggedInToken).pipe(take(1))
      .subscribe(authToken => token = authToken ?? "");
    return {
      Authorization: `Bearer ${token}`
    };
  }

  startListening() {
    this.connection.on("NewNotificationForUser", (notification: NotificationsEntity) =>
      this.store.dispatch(NotificationsState.NotificationsActions.newNotification({ notification }))
    );
  }

在“启动时的.net”中,services.AddSignalR();ConfigureServices下,

代码语言:javascript
复制
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapHub<NotificationHub>("/hubs/notificationhub");
});

Configure

我的集线器有一个[Authorize]属性。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-09 23:40:16

您可能没有处理access_token查询字符串参数。这在使用WebSockets时是必需的,因为WebSockets的浏览器API不支持设置标头。

文档解释了如何处理查询字符串https://learn.microsoft.com/aspnet/core/signalr/authn-and-authz?view=aspnetcore-7.0#built-in-jwt-authentication

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74376767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档