APIM 应用身份管理与授权最佳实践(使用 Microsoft Entra ID + Client Credentials Flow)

4 阅读4分钟

APIM 应用身份管理与授权最佳实践(使用 Microsoft Entra ID + Client Credentials Flow)

在微服务和企业级 API 管理场景中,如何安全、统一地管理后端 API 的访问身份和授权,是一个核心挑战。本文分享一种成熟的设计方案:通过 Azure API Management (APIM) 统一代理所有 API,并使用 Microsoft Entra ID(原 Azure AD) 集中管理所有消费应用的身份认证与授权。

整体设计思路

  • 所有需要被保护的 API 均通过 APIM 进行代理和暴露。
  • 任何调用 API 的应用(客户端/服务)均使用 Entra ID App Registration 进行身份注册。
  • 采用 Client Credentials Flow(应用到应用的无用户认证模式)获取 JWT Access Token。
  • APIM 在入口处使用 <validate-azure-ad-token> 策略对 Token 进行严格校验。
  • 授权逻辑基于 Entra ID 中的应用角色(App Roles) 实现,实现细粒度权限控制。

这种设计实现了身份集中管理安全解耦易于运维的目标。

Entra ID 中的应用注册与角色设计

所有配置均在 Microsoft Entra admin centerentra.microsoft.com)中完成。

1. 在 APIM 网关对应的 App Registration 上定义角色(推荐做法)
  • App Registration 名称示例:abc-int-apigw(或 apim-backend-api)
  • 在该应用中定义 App Roles(应用角色):
    • 示例:demoApp01-Role
    • 类型选择 Application(因为使用的是 client credentials flow)

为什么角色定义在网关/后端 API 的 App Registration 上?
因为这是 Token 的 Audience(受众)所属的应用,只有该应用才能暴露角色并让 Token 携带这些角色信息。

2. 在客户端应用(Client App)中授予权限
  • App Registration 名称示例:demoApp01
  • 进入 API permissionsAdd a permissionMy APIs
  • 选择上面定义角色的应用(abc-int-apigw 或 apim-backend-api)
  • 选择 Application permissions,勾选 demoApp01-Role
  • 完成 Grant admin consent for [Tenant](管理员同意)
3. 使用 Client Credentials Flow 获取 Token
curl --request POST \
  --url https://login.microsoftonline.com/fffffcf9-5044-49a6-9935-fc23fc1b43c2/oauth2/v2.0/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data client_id=66bf753e-ffff-4963-bd77-c4f2fac14e7f \
  --data 'client_secret=WcI8Q~k9CgMC3uaUy2HpnQY6narD_AWvMCpr5dyi' \
  --data scope=api://6da34051-a52b-ffff-8b59-50c5a4630bde/.default

关键点
scope 必须使用 abc-int-apigw(或对应后端 API)的 Application ID URI + /.default

返回的 Token 中会包含 "roles": ["demoApp01-Role"]

APIM 中的 Token 校验配置

1. 基础 API 调用(带 Subscription Key)
curl --request GET \
  --url https://abc-int-apigw.azure-api.net/test \
  --header 'Ocp-Apim-Subscription-Key: 5970de966fca496e84214e7ade9fc6ba'

(也可自定义 Header 为 X-API-KEY 等)

2. 推荐的 Inbound 策略(优化版)
<inbound>
    <base />
    <validate-azure-ad-token 
        tenant-id="fffffcf9-5044-49a6-9935-fc23fc1b43c2"
        header-name="Authorization"
        require-scheme="Bearer"
        failed-validation-httpcode="401"
        failed-validation-error-message="Unauthorized. Missing or invalid Azure AD token with required role.">
        
        <!-- 支持两种常见的 audience 格式(推荐) -->
        <audiences>
            <audience>api://6da34051-a52b-ffff-8b59-50c5a4630bde</audience>
            <audience>6da34051-a52b-ffff-8b59-50c5a4630bde</audience>
        </audiences>
        
        <!-- 强制要求应用角色 -->
        <required-claims>
            <claim name="roles" match="any">
                <value>demoApp01-Role</value>
            </claim>
        </required-claims>
    </validate-azure-ad-token>
</inbound>

改进建议

  • 使用 Named Values 管理 tenant-idaudience 和角色名称,便于多环境切换(Dev/Test/Prod)。
  • 可进一步添加 <on-error> 策略,实现更友好的自定义错误消息(区分 audience 错误 vs 角色缺失)。
3. 带 Token 的完整调用示例
curl --request GET \
  --url https://abc-int-apigw.azure-api.net/test \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlUxc1g4WUZIUzdaNlZsN1ZITEl6VGVqYnZqMCIsImtpZCI6IlUxc1g4WUZIUzdaNlZsN1ZITEl6VGVqYnZqMCJ9...' \
  --header 'X-API-KEY: 5970de966fca496e84214e7ade9fc6ba'

成功响应示例:

{
    "sampleField": "test"
}

使用不正确角色(或缺少角色)的 Token 时,返回:

{
    "statusCode": 401,
    "message": "Unauthorized. Missing or invalid Azure AD token with required role."
}

最佳实践总结

  1. Audience 配置:同时支持 api://GUID 和纯 GUID 两种格式,避免常见校验失败。
  2. 角色类型:Client Credentials Flow 必须使用 Application 类型的 App Roles。
  3. 安全性:始终保留 Audience 检查;建议结合 Subscription Key + JWT 双重保护。
  4. 可维护性:优先使用 APIM Named Values + Policy Fragments。
  5. 错误处理:通过 failed-validation-error-message<on-error> 提供清晰的提示信息。
  6. 权限授予:务必执行 Admin Consent,否则 Token 中不会出现角色。

这种架构已在多个企业项目中验证有效,实现了统一身份管理细粒度授权高安全性的平衡。