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

Angular SSR未等待AWS Cognito令牌获取,求合规解决方案

Angular SSR 等待Amplify Auth会话的原生解决方案

针对你遇到的Angular SSR渲染时不等待Amplify Auth会话初始化、返回HTML仅含加载指示器的问题,在Angular 17中可以采用以下两种原生方案替代宏任务hack:

方案1:服务器端预获取令牌并注入应用

核心思路是在Angular应用渲染前,由SSR服务端提前完成Auth会话的获取,将令牌作为注入令牌传递给应用,避免在Apollo链路中异步等待:

  1. 定义注入令牌
import { InjectionToken } from '@angular/core';

export const SSR_AUTH_TOKEN = new InjectionToken<string | undefined>('SSR_AUTH_TOKEN');
  1. 修改server.ts的请求处理逻辑
app.get('*', async (req, res) => {
  let authToken: string | undefined;
  try {
    // 配置SSR端的Amplify Auth存储
    const ssrAuthConfig = {
      ...yourAmplifyConfig,
      storage: new UniversalStorage({ req })
    };
    Auth.configure(ssrAuthConfig);
    
    // 预获取会话令牌
    const session = await Auth.currentSession();
    authToken = session.getAccessToken().getJwtToken();
  } catch (err) {
    authToken = undefined;
  }

  // 渲染应用时注入令牌
  const html = await renderApplication(AppComponent, {
    document: indexHtml,
    url: req.originalUrl,
    platformProviders: [
      { provide: REQUEST, useValue: req },
      { provide: SSR_AUTH_TOKEN, useValue: authToken }
    ]
  });

  res.send(html);
});
  1. 更新Apollo客户端配置
export function createApollo(
  platformId: Object,
  @Optional() ssrAuthToken: string | undefined
) {
  return {
    cache,
    link: ApolloLink.from([
      setContext(async () => {
        // SSR端直接使用预注入的令牌
        if (!isPlatformBrowser(platformId) && ssrAuthToken) {
          return authHeaders(ssrAuthToken);
        }

        // 客户端保留原有异步获取逻辑
        try {
          const session = await Auth.currentSession();
          return authHeaders(session.getAccessToken().getJwtToken());
        } catch {
          return unAuthHeaders();
        }
      }),
      httpLink.create({ uri: environment.graphqlEndpoint })
    ])
  };
}

// 在app.config.ts中注册Apollo配置
export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [PLATFORM_ID, [new Optional(), SSR_AUTH_TOKEN]]
    }
  ]
};

方案2:使用APP_INITIALIZER全局初始化Auth会话

通过Angular的APP_INITIALIZER钩子,强制SSR在应用渲染前完成Auth会话初始化:

  1. 创建Auth会话服务
@Injectable({ providedIn: 'root' })
export class AuthSessionService {
  private token: string | undefined;

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
    @Optional() @Inject(REQUEST) private request: Request
  ) {}

  async initSession(): Promise<void> {
    if (isPlatformBrowser(this.platformId)) return;

    // SSR端配置Auth并获取令牌
    const ssrAuthConfig = {
      ...yourAmplifyConfig,
      storage: new UniversalStorage({ req: this.request })
    };
    Auth.configure(ssrAuthConfig);

    try {
      const session = await Auth.currentSession();
      this.token = session.getAccessToken().getJwtToken();
    } catch {
      this.token = undefined;
    }
  }

  getToken(): string | undefined {
    return this.token;
  }
}
  1. 在app.config.ts中注册初始化钩子
export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: (authSessionService: AuthSessionService) => () => authSessionService.initSession(),
      deps: [AuthSessionService],
      multi: true
    }
  ]
};
  1. 修改Apollo配置使用预初始化令牌
export function createApollo(authSessionService: AuthSessionService) {
  return {
    cache,
    link: ApolloLink.from([
      setContext(async () => {
        const token = authSessionService.getToken();
        if (token) {
          return authHeaders(token);
        }

        // 客户端逻辑不变
        try {
          const session = await Auth.currentSession();
          return authHeaders(session.getAccessToken().getJwtToken());
        } catch {
          return unAuthHeaders();
        }
      }),
      httpLink.create({ uri: environment.graphqlEndpoint })
    ])
  };
}

原NgZone方案无效的原因

Amplify Auth的异步操作可能脱离了Angular Zone的上下文,导致Angular无法追踪该宏任务。上述两种方案要么将异步操作移至应用渲染前,要么通过Angular原生初始化钩子强制等待,均无需依赖hack手段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 14:04:53