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

Angular项目首次调用OidcSecurityService.getAccessToken()返回null问题

解决Angular OIDC拦截器首次请求Token为null的问题

问题分析

当前代码的核心问题在于:拦截器构造函数中订阅getAccessToken()是异步操作,但首次页面渲染时,第一个API请求会在token订阅回调触发前就执行,导致this.token仍为null。后续请求正常是因为此时token已经通过订阅回调被赋值,刷新页面后OIDC服务会从缓存中快速加载token,所以请求也能正常获取到。

解决方案

1. 拦截器内直接异步处理Token

不要在构造函数中缓存token,而是在intercept方法里直接订阅getAccessToken()的Observable,通过RxJS的switchMap操作符确保拿到token后再处理请求,避免异步时序问题。

修改后的拦截器代码:

import { Injectable } from "@angular/core";
import { Observable, switchMap } from "rxjs";
import {
  HttpInterceptor,
  HttpEvent,
  HttpRequest,
  HttpHandler,
} from "@angular/common/http";
import { OidcSecurityService } from "angular-auth-oidc-client";
import { Router } from "@angular/router";
import { TokenValidatorService } from "../../services/token-validator.service";

export const UseOidcInterceptorHeader = "X-Oidc-Interceptor";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor(
    private oidcSecurityService: OidcSecurityService,
    private tokenValidatorService: TokenValidatorService,
    private router: Router
  ) {}

  intercept(
    req: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    // 跳过认证服务器的请求,避免循环拦截
    if (req.url.includes("companyAuthServer")) {
      return next.handle(req);
    }

    // 订阅token流,确保拿到有效token后再处理请求
    return this.oidcSecurityService.getAccessToken().pipe(
      switchMap((token) => {
        if (!token) {
          console.error(
            "OidcSecurityService, token not fetched: NO authorize header!",
            req.urlWithParams
          );
          // 内部应用强制认证,直接跳转到登录页
          this.router.navigate(["/oidc/login"]);
          return next.handle(req);
        }

        // 验证用户AD组权限
        if (!this.tokenValidatorService.checkUserIsInAdGroup(token)) {
          this.router.navigate(["/oidc/unauthorized"]);
          return next.handle(req);
        }

        // 克隆请求并添加Bearer Token头
        const requestForward = req.clone({
          setHeaders: { Authorization: `Bearer ${token}` },
        });

        return next.handle(requestForward);
      })
    );
  }
}

2. 应用初始化前完成OIDC认证检查

为了彻底避免首次请求时token未加载的问题,在应用初始化阶段调用OIDC服务的checkAuth()方法,确保用户完成认证后再加载应用内容。

在app.module.ts中配置APP_INITIALIZER:

import { APP_INITIALIZER, NgModule } from '@angular/core';
import { OidcSecurityService } from 'angular-auth-oidc-client';

// 初始化OIDC认证检查
export function initOidc(oidcSecurityService: OidcSecurityService) {
  return () => oidcSecurityService.checkAuth();
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initOidc,
      deps: [OidcSecurityService],
      multi: true
    }
  ]
})
export class AppModule { }

关键说明

  • 使用switchMap将token流与请求流合并,保证每次请求都能获取到最新的token值,同时处理异步时序问题。
  • APP_INITIALIZER会在应用启动前执行OIDC认证检查,确保用户已登录且token已加载,从根源上解决首次请求无token的问题。
  • 保留了权限验证逻辑,确保不符合AD组要求的用户被导航到未授权页面。

内容的提问来源于stack exchange,提问作者Alf Kåre Lefdal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 05:08:09