如何以委派管理员权限非交互式批量为应用授予管理员同意(C#)
批量自动授予多租户应用权限(C#实现)
可以通过Microsoft Graph API实现批量自动化授权,无需手动访问管理员同意页面。核心思路是利用合作伙伴管理员账号的权限,调用Graph API直接为客户租户中的多租户应用分配应用权限。
前提条件
- 你的合作伙伴账号需在每个目标客户租户中拥有全局管理员或应用程序管理员角色(仅这类角色能授予应用级权限的管理员同意)
- 你的多租户应用已在自身租户完成注册
- 用于调用Graph API的身份(可以是合作伙伴应用的Client Credential,或管理员账号的用户名密码)需具备上述租户权限
实现步骤及C#代码
1. 安装依赖包
安装Microsoft Graph相关NuGet包:
Install-Package Microsoft.Graph Install-Package Azure.Identity
2. 批量授权代码示例
using Microsoft.Graph; using Azure.Identity; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace TenantPermissionGrant { class Program { static async Task Main(string[] args) { // 配置参数 var config = new { PartnerClientId = "你的合作伙伴应用ID", // 用于调用Graph的应用ID PartnerClientSecret = "你的合作伙伴应用密钥", TargetMultiTenantAppId = "你的多租户应用ID", // 需要授权的多租户应用ID GraphAppId = "00000003-0000-0000-c000-000000000000", // Microsoft Graph固定应用ID TargetTenantIds = new List<string> { "客户租户ID1", "客户租户ID2" }, // 批量处理的租户ID列表 RequiredPermissions = new List<string> { "User.Read.All", "Group.Read.All" } // 需要授予的应用权限 }; foreach (var tenantId in config.TargetTenantIds) { Console.WriteLine($"开始处理租户: {tenantId}"); await GrantPermissionsToTenant(tenantId, config); } } static async Task GrantPermissionsToTenant(string tenantId, dynamic config) { try { // 初始化Graph客户端(使用Client Credential Flow) var credential = new ClientSecretCredential(tenantId, config.PartnerClientId, config.PartnerClientSecret); var graphClient = new GraphServiceClient(credential); // 步骤1:获取目标多租户应用在客户租户中的服务主体 var targetSp = await graphClient.ServicePrincipals .Request() .Filter($"appId eq '{config.TargetMultiTenantAppId}'") .GetAsync(); if (targetSp.Count == 0) { // 若服务主体不存在,手动创建(多租户应用首次访问会自动生成,此步骤为兜底) var newSp = new ServicePrincipal { AppId = config.TargetMultiTenantAppId }; targetSp.Add(await graphClient.ServicePrincipals.Request().AddAsync(newSp)); } var targetSpId = targetSp[0].Id; // 步骤2:获取Microsoft Graph的服务主体信息(包含权限列表) var graphSp = await graphClient.ServicePrincipals .Request() .Filter($"appId eq '{config.GraphAppId}'") .Expand("appRoles") .GetAsync(); var graphSpId = graphSp[0].Id; var availablePermissions = graphSp[0].AppRoles .Where(ar => ar.AllowedMemberTypes.Contains("Application")) .ToDictionary(ar => ar.Value, ar => ar.Id); // 步骤3:批量分配所需权限 foreach (var perm in config.RequiredPermissions) { if (!availablePermissions.TryGetValue(perm, out var permId)) { Console.WriteLine($"租户{tenantId}:未找到权限{perm}"); continue; } // 检查权限是否已存在,避免重复分配 var existingAssignments = await graphClient.ServicePrincipals[targetSpId].AppRoleAssignments .Request() .Filter($"resourceId eq '{graphSpId}' and appRoleId eq '{permId}'") .GetAsync(); if (existingAssignments.Count > 0) { Console.WriteLine($"租户{tenantId}:权限{perm}已存在"); continue; } // 创建权限分配 var assignment = new AppRoleAssignment { PrincipalId = Guid.Parse(targetSpId), ResourceId = Guid.Parse(graphSpId), AppRoleId = Guid.Parse(permId) }; await graphClient.ServicePrincipals[targetSpId].AppRoleAssignments .Request() .AddAsync(assignment); Console.WriteLine($"租户{tenantId}:成功授予权限{perm}"); } } catch (ServiceException ex) { Console.WriteLine($"租户{tenantId}处理失败:{ex.Message}"); } } } }
关键注意事项
- 权限检查:代码中加入了重复权限检测,避免重复提交请求
- 错误处理:捕获ServiceException,便于排查授权失败原因(如权限不足、租户不存在等)
- 替代身份验证:如果无法使用Client Credential Flow,也可以使用
UsernamePasswordCredential(需禁用MFA,不推荐生产环境)
内容的提问来源于stack exchange,提问作者Tobias
相关产品推荐
相关产品推荐

