Angular Apollo动态添加请求头失效及启动期获取JWT方案咨询
解答
1. 请求级别添加Authorization头无效的原因
- 全局拦截器覆盖上下文:如果你的Apollo Client配置了全局拦截器,拦截器可能会重写请求上下文的headers,导致手动设置的Authorization头被覆盖或忽略。
- 上下文配置格式错误:
apollo-angular中,请求级别的headers需要通过operation.setContext传递,直接在watchQuery的context.headers里设置可能不被HttpLink识别,正确方式是将headers放在context的顶层headers字段,同时确保HttpLink能正确读取该配置。 - 令牌值异常:如果
getAccessToken$()返回空值或未正确解析,会生成Bearer undefined的无效头,浏览器会自动忽略这个无效头,不会发送到后端。 - CORS配置限制:虽然硬编码令牌时有效,但如果后端CORS配置在某些场景下未允许Authorization头,也可能导致头被移除,不过该概率较低。
2. 应用启动阶段获取JWT的可行方案
方案一:调整APP_INITIALIZER依赖顺序,先初始化Auth0
将Auth0服务注册在Apollo的APP_INITIALIZER之前,确保Auth0先完成实例化,再在Apollo初始化逻辑中获取令牌:
@NgModule({ providers: [ Auth0Service, // 优先注册Auth0服务 ApolloOptionsService, { provide: APP_INITIALIZER, useFactory: async (auth0: Auth0Service, apolloOpts: ApolloOptionsService) => { // 先获取JWT令牌 const accessToken = await auth0.getAccessToken(); // 传入令牌初始化Apollo Client return await lastValueFrom( apolloOpts.createApollo$(accessToken) .pipe(filter(val => !!val), take(1)) ); }, deps: [Auth0Service, ApolloOptionsService], multi: true }, // 其他Apollo相关提供者... ] }) export class GraphQLModule {}
方案二:用Apollo全局拦截器自动注入令牌
通过Apollo Link拦截所有请求,异步获取令牌并添加到请求头,无需在每个请求中手动设置:
import { ApolloLink, Observable } from '@apollo/client/core'; import { HttpLink } from 'apollo-angular/http'; export function createAuthLink(auth0Service: Auth0Service): ApolloLink { return new ApolloLink((operation, forward) => { return new Observable(observer => { auth0Service.getAccessToken$().subscribe({ next: token => { operation.setContext({ headers: { Authorization: token ? `Bearer ${token}` : '' } }); forward(operation).subscribe(observer); }, error: err => observer.error(err) }); }); }); } // 在GraphQLModule中配置 @NgModule({ providers: [ { provide: APOLLO_OPTIONS, useFactory: (httpLink: HttpLink, auth0Service: Auth0Service) => { const authLink = createAuthLink(auth0Service); const http = httpLink.create({ uri: '你的GraphQL接口地址' }); return { link: authLink.concat(http), cache: new InMemoryCache() }; }, deps: [HttpLink, Auth0Service] } ] }) export class GraphQLModule {}
方案三:将Auth0初始化放入APP_INITIALIZER
如果Auth0自身需要异步初始化,把这个逻辑放到APP_INITIALIZER中,确保应用启动前Auth0已就绪:
export function initAuth0(auth0Service: Auth0Service) { return async () => { await auth0Service.initialize(); // 调用Auth0的异步初始化方法 }; } @NgModule({ providers: [ Auth0Service, { provide: APP_INITIALIZER, useFactory: initAuth0, deps: [Auth0Service], multi: true }, // 后续加载Apollo相关的APP_INITIALIZER... ] }) export class AppModule {}
内容的提问来源于stack exchange,提问作者john
相关产品推荐
相关产品推荐

