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

能否使用服务主体或Azure应用管理员同意外部多租户应用注册?

问题

我们管理多个租户,目前创建多租户应用注册后,需要逐个在浏览器中加载管理员同意URL,以管理员身份登录每个租户操作,过程十分繁琐。此前我可通过PowerShell及密码数据库执行Login-AzureRmAccount获取刷新令牌,调用端点https://main.iam.ad.ext.azure.com/api/RegisteredApplications/$azureAppId/Consent?onBehalfOfAll=true批准各租户应用。但如今受MFA及安全加固政策影响,已无法以管理员身份程序化登录完成批准。

现提问:

  • 能否使用在每个租户创建的服务主体程序化登录,批准该租户的应用注册?
  • 还是仅允许使用用户名密码的普通管理员账户执行批准?
  • 是否有该流程的可用示例代码?

已执行测试

我创建了拥有Directory.ReadWrite.All权限的应用注册,测试了类似如下代码及多种变体但均失败,根据输入资源不同出现不同错误:

错误1:

Invoke-RestMethod : {"error":"invalid_resource","error_description":"AADSTS500011: The resource principal named <a href="https://graph.microsoft.com/.default" rel="nofollow noreferrer">https://graph.microsoft.com/.default was not found in the tenant name

错误2:

Invoke-WebRequest : The remote server returned an error: (401) Unauthorized.

测试代码:

$body = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    resource      = $resourceAppIdURI
}
$oauth = Invoke-RestMethod -Method Post -Uri https://login.windows.net/$tenantId/oauth2/token?api-version=1.0 -Body $body

$header = @{
    'Authorization' = 'Bearer ' + $apiToken.access_token
    'X-Requested-With'= 'XMLHttpRequest'
    'x-ms-client-request-id'= [guid]::NewGuid()
    'x-ms-correlation-id' = [guid]::NewGuid()
}
$url = "https://main.iam.ad.ext.azure.com/api/RegisteredApplications/$azureAppId/Consent?onBehalfOfAll=true"
解答
  1. 能否使用服务主体完成租户应用批准?
    可以,但需满足两个核心条件:
  • 目标租户中的服务主体必须拥有**Application.ReadWrite.All或Directory.ReadWrite.All的应用权限**(注意是应用权限而非委派权限),且该权限已由目标租户管理员完成管理员同意。
  • 不能继续使用main.iam.ad.ext.azure.com端点,该端点属于Azure Portal内部API,不支持服务主体调用,需改用Microsoft Graph API完成操作。
  1. 是否仅允许用户名密码的管理员账户执行批准?
    不是。除受MFA限制的用户名密码流程外,还支持:
  • 满足权限要求的服务主体调用Microsoft Graph API(完全自动化)。
  • 支持MFA的交互式登录流程(如设备代码流),但仍需人工交互,不适用于批量自动化场景。
  1. 示例代码(PowerShell + Microsoft Graph API)
    以下是使用服务主体完成租户级应用管理员同意的可运行示例:
# 配置参数
$tenantId = "目标租户ID"
$servicePrincipalClientId = "服务主体的应用ID"
$servicePrincipalSecret = "服务主体的客户端密钥"
$targetMultiTenantAppId = "需要被批准的多租户应用ID"
$requiredScopes = "User.Read.All Directory.ReadWrite.All" # 替换为目标应用实际需要的权限范围

# 获取Microsoft Graph访问令牌
$tokenUri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$tokenBody = @{
    grant_type    = "client_credentials"
    client_id     = $servicePrincipalClientId
    client_secret = $servicePrincipalSecret
    scope         = "https://graph.microsoft.com/.default"
}
$tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenUri -Body $tokenBody

# 构建请求头
$headers = @{
    "Authorization" = "Bearer $($tokenResponse.access_token)"
    "Content-Type"  = "application/json"
}

# 查询目标应用在租户中的服务主体ID
$spQueryUri = "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=appId eq '$targetMultiTenantAppId'"
$targetSp = Invoke-RestMethod -Uri $spQueryUri -Headers $headers
if (-not $targetSp.value) {
    Write-Host "目标应用未在当前租户中注册,请先让租户用户访问应用触发服务主体创建"
    exit
}
$targetSpId = $targetSp.value[0].id

# 调用Graph API完成租户级管理员同意
$consentUri = "https://graph.microsoft.com/v1.0/oauth2PermissionGrants"
$consentBody = @{
    clientId = $targetMultiTenantAppId
    consentType = "AllPrincipals"
    resourceId = $targetSpId
    scope = $requiredScopes
} | ConvertTo-Json

try {
    $response = Invoke-RestMethod -Method Post -Uri $consentUri -Headers $headers -Body $consentBody
    Write-Host "应用同意已成功完成"
} catch {
    Write-Host "同意失败:$($_.Exception.Message)"
    if ($_.ErrorDetails.Message) {
        Write-Host "详细错误:$($_.ErrorDetails.Message)"
    }
}

关键注意事项

  • 需先在目标租户中创建服务主体(可通过Azure AD门户或New-AzADServicePrincipal命令),并为其分配Application.ReadWrite.All应用权限,由租户管理员完成权限同意。
  • 目标多租户应用需先被租户用户访问过一次,确保其服务主体已在目标租户中创建,否则查询servicePrincipals会返回空结果。
  • requiredScopes需严格匹配目标应用注册时定义的权限范围,不能随意添加未声明的权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:14:56