You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular11中如何通过Azure Function的SignalR协商实现token过期后续权

解决方案

问题根因

你当前的代码中accessTokenFactory返回的是第一次调用协商接口获取的静态token,Azure SignalR Service默认返回的该类token有效期为1小时,过期后无论是重连还是轮询类传输请求都会返回401未授权错误。

修复步骤

前端signalr.service.ts修改

核心调整逻辑:将accessTokenFactory改为异步函数,每次SignalR需要验证token时(包括初始握手、重连、轮询请求校验)主动拉取最新的有效token,同时优化连接初始化逻辑避免重复创建连接。

修改后代码如下:

import * as signalR from '@microsoft/signalr';
import { Subject, firstValueFrom } from 'rxjs'; // 导入firstValueFrom把Observable转Promise

orderMessages: Subject<any> = new Subject();
saleMessages: Subject<any> = new Subject();
hubConnection?: signalR.HubConnection;
     
private getConnectionInfo(): Observable<SignalRConnectionInfo> {
   return this.http.get<SignalRConnectionInfo>('http://localhost:7071/api/SignalRNegotiationFunction');
}
    
async init() {
  // 避免重复初始化连接
  if (this.hubConnection) {
    await this.hubConnection.stop();
  }

  // 首次拉取连接信息获取SignalR服务端点
  const firstInfo = await firstValueFrom(this.getConnectionInfo());
  let options = {
    // accessTokenFactory支持返回Promise,每次需要token时自动拉取最新协商结果
    accessTokenFactory: async () => {
      const info = await firstValueFrom(this.getConnectionInfo());
      return info.accessToken;
    }
  };

  this.hubConnection = new signalR.HubConnectionBuilder()
    .withUrl(firstInfo.url, options)
    .withAutomaticReconnect([0, 1000, 5000, 10000, 30000]) // 可调整重试策略,移除null避免停止重试
    .configureLogging(signalR.LogLevel.Information)        
    .build();

  // 重连成功回调可选,按需添加业务逻辑
  this.hubConnection.onreconnected(() => {
    console.log('SignalR重连成功,已自动刷新token');
  });

  // 重连失败回调可选
  this.hubConnection.onclose((err) => {
    console.error('SignalR连接关闭', err);
    // 按需添加重试初始化逻辑
  });

  this.hubConnection.off('notifyresult');
  this.hubConnection.on('notifyresult', (data: any) => {
    if(data == "Orders") {
      this.orderMessages.next(data);
    } else {
      this.saleMessages.next(data);
    }
  });

  try {
    await this.hubConnection.start();
  } catch (err) {
    console.error('SignalR启动失败', err.toString());
  }
}

可选优化:添加token缓存减少接口请求

如果需要避免每次token校验都调用协商接口,可以添加缓存逻辑,提前5分钟刷新token即可:

private cachedToken?: string;
private tokenExpireTime?: number;

private async getValidToken(): Promise<string> {
  // 缓存未过期直接返回缓存的token,提前5分钟刷新
  if (this.cachedToken && Date.now() < (this.tokenExpireTime || 0) - 5 * 60 * 1000) {
    return this.cachedToken;
  }
  const info = await firstValueFrom(this.getConnectionInfo());
  this.cachedToken = info.accessToken;
  // 协商接口返回的token默认有效期1小时,设置过期时间
  this.tokenExpireTime = Date.now() + 60 * 60 * 1000;
  return this.cachedToken;
}

// 对应的accessTokenFactory修改为调用该方法
accessTokenFactory: () => this.getValidToken()

后端Azure Function优化建议

你当前的协商接口设置为匿名权限,生产环境建议添加业务身份校验,只有合法登录的用户才能调用接口获取token,避免未授权用户滥用SignalR服务。

注意事项

  • WebSocket协议下token仅在握手阶段校验,连接保持期间不会校验token有效期,只有断开重连时才会拉取新token,上述方案已经覆盖该场景
  • 长轮询、SSE传输协议下每次请求都会校验token,上述异步拉取新token的逻辑可以自动处理过期问题,不需要额外手动刷新连接

内容的提问来源于stack exchange,提问作者RGS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 12:24:03