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

如何生成可同时访问MS Graph API与自定义API的通用访问令牌?

解决方案:Azure AD多资源令牌获取与角色授权(Angular + MSAL v3)

核心结论

不存在同时面向Microsoft Graph API和自定义Python API的通用访问令牌。访问令牌的aud(受众)字段是单一资源标识符,这是OAuth2/OpenID Connect的标准要求,Azure AD严格执行此规则。你需要分别获取针对两个资源的独立令牌,但可以通过MSAL的内存缓存机制安全管理,避免存储到本地/会话存储。


1. MSAL v3 Angular配置(内存缓存模式)

在Angular的app.module.ts中配置MSAL,强制使用内存缓存,避免令牌持久化到浏览器存储:

import { NgModule } from '@angular/core';
import { MsalModule, MsalService, MSAL_INSTANCE } from '@azure/msal-angular';
import { PublicClientApplication, BrowserCacheLocation } from '@azure/msal-browser';

export function MSALInstanceFactory(): PublicClientApplication {
  return new PublicClientApplication({
    auth: {
      clientId: '<你的SPA应用Client ID>',
      authority: 'https://login.microsoftonline.com/<你的租户ID>',
      redirectUri: '<你的SPA重定向URI>',
    },
    cache: {
      cacheLocation: BrowserCacheLocation.Memory, // 仅存内存,页面刷新后清空
      storeAuthStateInCookie: false, // 禁用Cookie存储
    },
  });
}

@NgModule({
  imports: [
    MsalModule.forRoot(
      new PublicClientApplication({
        auth: {
          clientId: '<你的SPA应用Client ID>',
          authority: 'https://login.microsoftonline.com/<你的租户ID>',
          redirectUri: '<你的SPA重定向URI>',
        },
        cache: {
          cacheLocation: BrowserCacheLocation.Memory,
          storeAuthStateInCookie: false,
        },
      }),
      {
        protectedResourceMap: new Map([
          // 自定义Python API的资源映射
          ['https://your-python-api-domain/*', ['api://<你的Web API应用Client ID>/Files.Read']],
          // Microsoft Graph API的资源映射
          ['https://graph.microsoft.com/v1.0/me/appRoleAssignments', ['Directory.Read.All', 'User.Read']],
        ]),
      }
    ),
  ],
  providers: [
    {
      provide: MSAL_INSTANCE,
      useFactory: MSALInstanceFactory,
    },
    MsalService,
  ],
})
export class AppModule {}

2. 获取双资源令牌

在Angular服务(比如AuthService)中封装令牌获取逻辑,MSAL会自动管理内存缓存,重复请求会直接返回缓存的令牌:

import { Injectable } from '@angular/core';
import { MsalService } from '@azure/msal-angular';
import { AuthenticationResult } from '@azure/msal-browser';

@Injectable({ providedIn: 'root' })
export class AuthService {
  constructor(private msalService: MsalService) {}

  // 获取自定义Python API的访问令牌
  async getApiToken(): Promise<string> {
    const result: AuthenticationResult = await this.msalService.acquireTokenSilent({
      scopes: ['api://<你的Web API应用Client ID>/Files.Read'],
    });
    return result.accessToken;
  }

  // 获取Microsoft Graph API的访问令牌
  async getGraphToken(): Promise<string> {
    const result: AuthenticationResult = await this.msalService.acquireTokenSilent({
      scopes: ['Directory.Read.All', 'User.Read'],
    });
    return result.accessToken;
  }

  // 调用Graph API获取用户角色
  async getUserRoles(): Promise<string[]> {
    const token = await this.getGraphToken();
    const response = await fetch('https://graph.microsoft.com/v1.0/me/appRoleAssignments', {
      headers: { Authorization: `Bearer ${token}` },
    });
    const data = await response.json();
    // 提取角色名称(假设你的角色定义在appRole的displayName字段)
    return data.value.map((assignment: any) => assignment.appRole.displayName);
  }

  // 检查用户是否拥有指定角色
  async hasRole(roleName: string): Promise<boolean> {
    const roles = await this.getUserRoles();
    return roles.includes(roleName);
  }
}

3. 基于角色控制视图显示

在Angular组件中直接调用AuthService的方法控制视图:

<!-- 仅当用户拥有Admin角色时显示此组件 -->
<div *ngIf="authService.hasRole('Admin') | async">
  <h2>管理员控制面板</h2>
  <!-- 管理员专属内容 -->
</div>

<!-- 普通用户视图 -->
<div *ngIf="!(authService.hasRole('Admin') | async)">
  <h2>用户主页</h2>
  <!-- 普通用户内容 -->
</div>

4. 关键注意事项

  • 权限配置:需要在Azure AD的SPA应用中添加Microsoft Graph的Directory.Read.All(委派权限),并由租户管理员完成权限同意。
  • 令牌刷新:MSAL会自动处理令牌过期刷新,内存缓存中的令牌会被自动更新,无需手动干预。
  • 角色替代方案:如果你的自定义API令牌中已经包含roles声明(Azure AD会自动将分配的角色添加到令牌的roles字段),可以直接从API令牌中提取角色,无需调用Graph API,减少网络请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:17:22