如何用angular-oauth2-oidc获取自定义API与Microsoft Graph的独立令牌
解决Angular 18中用
angular-oauth2-oidc同时获取自定义API与Microsoft Graph令牌的方案 你之前反复重新配置OAuthService导致页面循环加载的核心原因是:每次重新配置后,服务会自动尝试处理路由回调,与初始登录的回调逻辑冲突,引发无限循环。以下是三种可行的解决方案,按推荐优先级排序:
方案一:用Refresh Token获取第二个令牌(推荐)
借助初始登录拿到的Refresh Token,无需二次跳转即可获取Graph API的专属令牌,是最流畅的实现方式。
步骤1:修改初始配置,添加offline_access权限
要获取Refresh Token,必须在初始登录的scope中加入offline_access:
// app.config.ts 中修改authCodeFlowConfig export const authCodeFlowConfig: AuthConfig = { issuer: environment.ISSUER, redirectUri: environment.REDIRECT_URI, clientId: environment.CLIENT_ID, responseType: environment.RESPONSE_TYPE, scope: `${environment.SCOPE} offline_access`, // 追加offline_access strictDiscoveryDocumentValidation: false, showDebugInformation: true, sessionChecksEnabled: true, silentRefreshRedirectUri: `${window.location.origin}?silent-refresh=true`, };
步骤2:登录成功后获取Graph令牌
在组件中完成初始登录后,调用refreshToken()方法传入Graph的scope,直接获取令牌:
import { OAuthService } from 'angular-oauth2-oidc'; import { authCodeFlowConfig } from './app.config'; constructor(private oauthService: OAuthService) {} async ngOnInit() { // 初始化并完成自定义API的登录 await this.oauthService.configure(authCodeFlowConfig); await this.oauthService.loadDiscoveryDocumentAndLogin(); if (this.oauthService.hasValidAccessToken()) { // 用Refresh Token获取Graph的令牌 const graphTokenResp = await this.oauthService.refreshToken({ scope: 'openid profile User.Read.All offline_access' }); // 存储Graph令牌,后续调用Graph API时使用 localStorage.setItem('graph_access_token', graphTokenResp.access_token); } }
方案二:增量授权(二次轻量跳转)
如果初始登录未请求Graph权限,可通过增量授权引导用户完成权限确认(已有Entra ID会话,无需重复输入密码)。
核心代码实现
import { OAuthService } from 'angular-oauth2-oidc'; import { authCodeFlowConfig, graphCodeFlowConfig } from './app.config'; constructor(private oauthService: OAuthService) {} async ngOnInit() { await this.oauthService.loadDiscoveryDocument(); const currentState = this.oauthService.state; if (currentState === 'graph-auth') { // 处理Graph授权回调 await this.oauthService.configure(graphCodeFlowConfig); await this.oauthService.tryLogin(); localStorage.setItem('graph_access_token', this.oauthService.getAccessToken()); // 恢复自定义API的配置 this.oauthService.configure(authCodeFlowConfig); } else { // 处理初始登录 await this.oauthService.configure(authCodeFlowConfig); const isLoggedIn = await this.oauthService.tryLogin(); if (!isLoggedIn) { this.oauthService.initCodeFlow(); } else { // 触发Graph增量授权 this.oauthService.configure(graphCodeFlowConfig); this.oauthService.initCodeFlow('graph-auth'); // 用state区分回调 } } }
方案三:使用两个独立的OAuthService实例
通过创建两个隔离的OAuthService实例,分别管理自定义API和Graph的认证上下文,适合需要完全隔离认证状态的场景。
步骤1:配置多实例
在app.config.ts中注册两个命名的OAuth客户端:
import { ApplicationConfig } from '@angular/core'; import { provideOAuthClient } from 'angular-oauth2-oidc'; import { authCodeFlowConfig, graphCodeFlowConfig } from './app.config'; export const appConfig: ApplicationConfig = { providers: [ provideOAuthClient(authCodeFlowConfig, 'backendAuth'), provideOAuthClient(graphCodeFlowConfig, 'graphAuth') ] };
步骤2:注入并使用多实例
在组件中分别注入两个实例,独立完成登录:
import { OAuthService } from 'angular-oauth2-oidc'; import { Inject } from '@angular/core'; constructor( @Inject('backendAuth') private backendOAuth: OAuthService, @Inject('graphAuth') private graphOAuth: OAuthService ) {} async ngOnInit() { // 初始化自定义API认证 await this.backendOAuth.loadDiscoveryDocumentAndLogin(); // 初始化Graph认证(复用Entra ID会话,无需重复登录) await this.graphOAuth.loadDiscoveryDocumentAndLogin(); }
关键注意事项
- 确保Entra ID客户端已添加Microsoft Graph的User.Read.All权限,且已获得管理员同意(若为租户级权限)
- 所有请求的scope必须是客户端已注册的权限
- 使用Refresh Token方案时,必须确保初始登录请求了
offline_accessscope - 存储多个令牌时,需明确区分用途,避免混淆调用
内容的提问来源于stack exchange,提问作者Ashil John
相关产品推荐
相关产品推荐

