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

如何用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_access scope
  • 存储多个令牌时,需明确区分用途,避免混淆调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 23:39:54