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

基于React+Express用Graph API构建Microsoft Partner Center自助服务门户遇权限问题求助

多租户登录改造 + Partner Center API集成分步指南

一、先解决客户无法登录的多租户问题

你当前的AD应用是单租户模式,所以只有你租户内的用户能登录,改成多租户即可:

  1. 登录Azure门户,找到你的AD应用注册
  2. 进入「概述」页,把「支持的账户类型」改成任何组织目录中的账户(多租户)(如果不需要个人微软账户,就选这个;需要的话选包含个人账户的选项)
  3. 在「身份验证」页,确认前端和后端的重定向URI都已正确添加(比如前端http://localhost:3000/auth/callback、后端http://localhost:5000/api/auth/callback)
  4. 更新认证代码:
    • 前端(msal-react):把auth配置里的authority从你的租户ID换成https://login.microsoftonline.com/common
      const msalConfig = {
        auth: {
          clientId: "你的AD应用ID",
          authority: "https://login.microsoftonline.com/common", // 多租户通用端点
          redirectUri: "http://localhost:3000/auth/callback"
        }
      };
      
    • 后端(Express + passport-azure-ad):把identityMetadata改成多租户配置,同时禁用 issuer 验证(或者指定允许的租户列表)
      const passport = require('passport');
      const OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
      
      passport.use(new OIDCStrategy({
        identityMetadata: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
        clientID: process.env.AZURE_AD_CLIENT_ID,
        clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
        redirectUrl: process.env.AZURE_AD_REDIRECT_URI,
        validateIssuer: false, // 多租户模式下禁用,或者配置allowedIssuers
        responseType: 'code id_token',
        responseMode: 'form_post',
        scope: ['openid', 'profile', 'https://api.partnercenter.microsoft.com/user_impersonation']
      }, (iss, sub, profile, accessToken, refreshToken, done) => {
        // 这里可以把用户的租户ID(profile.tenantId)存入会话
        return done(null, { profile, accessToken });
      }));
      

二、集成Partner Center API核心步骤

1. 配置AD应用的Partner Center权限

  • 进入Azure AD应用的「API权限」页,点击「添加权限」→ 选择「Microsoft Partner Center」
  • 添加所需的委派权限:比如PartnerCenter.Read.All(读取订阅/许可证)、PartnerCenter.Subscriptions.ReadWrite.All(创建订阅)、PartnerCenter.Licenses.ReadWrite.All(管理许可证)
  • 点击「授予管理员同意」(必须是合作伙伴账户的全局管理员操作)
  • 同时在Partner Center后台,把这个AD应用添加为「应用程序用户」,分配对应角色(比如代理管理员)

2. 后端获取Partner Center访问令牌

因为是客户登录后操作,需要用用户委派的令牌通过「on-behalf-of」流程交换Partner Center的令牌:

const axios = require('axios');

async function getPcAccessToken(userAccessToken) {
  const tokenUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
  const params = new URLSearchParams({
    grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    client_id: process.env.AZURE_AD_CLIENT_ID,
    client_secret: process.env.AZURE_AD_CLIENT_SECRET,
    assertion: userAccessToken,
    scope: 'https://api.partnercenter.microsoft.com/user_impersonation',
    requested_token_use: 'on_behalf_of'
  });

  const res = await axios.post(tokenUrl, params);
  return res.data.access_token;
}

3. 调用API实现业务功能

(1)获取客户的订阅详情

async function getCustomerSubscriptions(pcToken, customerTenantId) {
  const apiUrl = `https://api.partnercenter.microsoft.com/v1/customers/${customerTenantId}/subscriptions`;
  const res = await axios.get(apiUrl, {
    headers: {
      'Authorization': `Bearer ${pcToken}`,
      'Accept': 'application/json'
    }
  });
  return res.data.items; // 返回订阅列表
}

(2)获取客户的许可证详情

async function getCustomerLicenses(pcToken, customerTenantId) {
  const apiUrl = `https://api.partnercenter.microsoft.com/v1/customers/${customerTenantId}/licenses`;
  const res = await axios.get(apiUrl, {
    headers: {
      'Authorization': `Bearer ${pcToken}`,
      'Accept': 'application/json'
    }
  });
  return res.data.items; // 返回许可证列表
}

(3)为客户创建新订阅/添加托管服务

async function createCustomerSubscription(pcToken, customerTenantId, subscriptionPayload) {
  const apiUrl = `https://api.partnercenter.microsoft.com/v1/customers/${customerTenantId}/subscriptions`;
  const res = await axios.post(apiUrl, subscriptionPayload, {
    headers: {
      'Authorization': `Bearer ${pcToken}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    }
  });
  return res.data;
}

// 示例payload:
// const payload = {
//   offerId: "你的Partner Center产品Offer ID",
//   friendlyName: "客户自定义订阅名称",
//   quantity: 5, // 购买数量
//   billingCycle: "Monthly", // 计费周期
//   termDuration: "P1M"
// };

三、前端React功能实现

  1. 获取客户租户ID:登录后通过msal-react的useMsal钩子获取用户的租户ID(account.idTokenClaims.tid)
  2. 调用后端API:把租户ID传给后端,获取对应的订阅/许可证数据,然后渲染成列表(比如用Ant Design的Table组件)
  3. 添加服务表单:做一个表单让客户选择要添加的服务(可以提前从后端拉取Partner Center的产品列表),填写数量后提交到后端的创建订阅接口
  4. 权限校验:前端要确保用户只能看到自己租户的资源,后端也要验证用户的租户ID和请求的客户租户ID一致

四、关键注意事项

  • 权限隔离:后端必须校验用户的租户ID与请求的客户租户ID匹配,禁止跨租户访问
  • API限流:Partner Center API有请求次数限制,要处理429错误,实现指数退避重试
  • 错误处理:前端要展示友好错误提示,后端要捕获API异常并返回结构化错误信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:05:37