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

ABP商业版多标签页持续刷新及自动登出问题求助

解决ABP商业版多标签页无限刷新及access token过期登出问题

一、搞定多标签页令牌冲突引发的无限刷新

浏览器LocalStorage为所有标签页共享,多个标签页同时刷新令牌时会互相覆盖,进而触发无限循环。可以从两方面处理:

  • 监听LocalStorage同步令牌
    直接在app.component.ts中添加LocalStorage监听,当其他标签页更新令牌时,当前标签页同步更新本地令牌,避免重复发起刷新请求:
ngOnInit() {
  window.addEventListener('storage', (event) => {
    // 替换为你的OIDC存储键,格式一般为oidc.user:<授权地址>:<客户端ID>
    if (event.key === 'oidc.user:https://your-auth-server.com:your-client-id') {
      const newTokenData = JSON.parse(event.newValue || '{}');
      this.oidcSecurityService.setAuthorizationData(newTokenData);
    }
  });
}
  • 给令牌刷新加并发锁
    ABP默认的OAuth拦截器未处理并发刷新场景,自定义拦截器添加锁机制,确保同一时间仅一个标签页发起刷新请求:
// 自定义OAuth拦截器
@Injectable()
export class CustomOAuthInterceptor extends OAuthInterceptor {
  private isRefreshing = false;
  private refreshSubject = new Subject<any>();

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.oauthService.hasValidAccessToken()) {
      return next.handle(this.addAccessToken(req));
    } else if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshSubject.next(null);

      return this.oauthService.refreshToken().pipe(
        switchMap((token) => {
          this.isRefreshing = false;
          this.refreshSubject.next(token);
          return next.handle(this.addAccessToken(req));
        }),
        catchError((err) => {
          this.isRefreshing = false;
          this.refreshSubject.error(err);
          return this.handleError(err, req, next);
        })
      );
    } else {
      return this.refreshSubject.pipe(
        filter(token => token !== null),
        take(1),
        switchMap(token => next.handle(this.addAccessToken(req)))
      );
    }
  }
}

随后在app.module.ts中替换默认拦截器:

providers: [
  { provide: OAuthInterceptor, useClass: CustomOAuthInterceptor }
]

二、调整登出逻辑:仅在refresh token过期时登出

ABP默认在access token过期且刷新失败时直接登出,我们需要区分失败原因,仅在refresh token过期时触发登出:

  • 自定义OIDC失败事件处理
    在app.component.ts中监听刷新失败事件,根据错误类型判断是否登出:
ngOnInit() {
  this.oidcSecurityService.refreshTokenFailed$.subscribe((err) => {
    // 识别refresh token过期的错误特征
    if (err.error === 'invalid_grant' || err.error_description?.includes('refresh token')) {
      // 仅refresh token过期时执行登出
      this.oidcSecurityService.logoff();
    } else {
      // 其他错误场景重新发起授权
      this.oidcSecurityService.authorize();
    }
  });
}
  • 优化令牌过期配置
    在environment.ts中调整OIDC参数,减少刷新频率,降低多标签页冲突概率:
export const environment = {
  // ...其他配置
  oAuthConfig: {
    issuer: 'https://your-auth-server.com',
    clientId: 'your-client-id',
    accessTokenExpiringNotificationTime: 60, // 提前60秒通知access token过期
    refreshTokenRenewInSeconds: 300, // 提前5分钟刷新refresh token
    silentRenew: false, // 关闭静默刷新,避免多标签页冲突
    // ...其他配置
  }
};

三、验证默认项目配置

如果默认ABP项目就出现该问题,检查是否开启了silentRenew,开启的话直接关闭,改用上述手动刷新逻辑,可有效减少多标签页冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 21:40:57