Azure Function启用MSI访问AAD认证WebAPI时请求令牌出错
我之前刚好处理过一模一样的场景,给你梳理下关键的配置要点、代码实现,还有踩过的坑,应该能帮到你:
这些是最容易出错的基础环节,先逐一排查:
验证AppRole的分配有效性:你提到WebAPI的清单里配置了支持
Application类型的AppRole,但要注意:门户没法直接给MSI分配Application类型的AppRole,必须用PowerShell或者Graph API来完成。举个PowerShell的例子:New-AzureADServiceAppRoleAssignment -ObjectId <Function_MSI的对象ID> -PrincipalId <Function_MSI的对象ID> -ResourceId <WebAPI_AAD应用的对象ID> -Id <你定义的AppRole的ID>这里的几个ID要对应准确:ObjectId和PrincipalId都是Function系统分配标识的对象ID,ResourceId是WebAPI对应的AAD应用的对象ID,AppRole的ID则是你在WebAPI清单里写的那个角色的唯一ID。
WebAPI的AAD认证设置:确保WebAPI的「身份验证/授权」面板里,AAD认证是「已启用」状态,并且「未经身份验证的请求」设置为「拒绝」——这样只有带有效Token的请求才能进入。另外再核对下WebAPI的AAD应用清单,AppRole的
allowedMemberTypes必须包含Application,比如:"appRoles": [ { "allowedMemberTypes": ["Application"], "displayName": "WebAPI访问权限", "id": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "isEnabled": true, "description": "允许应用程序访问WebAPI", "value": "WebAPI.Access" } ]Function的MSI权限检查:在Function的「身份」->「系统分配的标识」里确认状态是开启的。虽然门户里可以添加权限,但Application类型的权限还是用上面的PowerShell分配AppRole更可靠,避免出现权限未生效的情况。
不管用哪种语言,核心逻辑都是通过MSI获取访问WebAPI的Token,再带着Token发起请求:
C#示例
using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.Azure.Services.AppAuthentication; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { // 初始化MSI Token提供者 var tokenProvider = new AzureServiceTokenProvider(); // 获取访问WebAPI的Token,参数填WebAPI的AAD应用客户端ID或者应用ID URI都可以 string accessToken = await tokenProvider.GetAccessTokenAsync("<WebAPI的客户端ID>"); // 发起请求 using (var client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); HttpResponseMessage response = await client.GetAsync("<WebAPI的接口地址>"); return response; } }
Python示例
import requests from azure.identity import ManagedIdentityCredential def main(req): # 初始化MSI凭证 credential = ManagedIdentityCredential() # 获取Token,scope格式是「WebAPI的应用ID URI」+ /.default token = credential.get_token("<WebAPI的应用ID URI>/.default") # 调用WebAPI headers = {"Authorization": f"Bearer {token.token}"} response = requests.get("<WebAPI的接口地址>", headers=headers) return response.text
这里要注意:获取Token时的资源/scope参数要和WebAPI的AAD应用配置匹配,用客户端ID或者应用ID URI都能生效,选你方便的就行。
如果遇到报错,按这个顺序查:
- Token获取失败:先确认Function的MSI是开启状态,再检查资源参数有没有写错。另外,Function的运行环境有没有权限访问Azure AD的Token端点(一般默认都有,除非是特殊的网络隔离环境)。
- WebAPI返回403 Forbidden:这大概率是Token里没有包含对应的角色声明。找个JWT解析工具解析下拿到的Token,看payload里的
roles字段有没有你分配的AppRole值。如果没有,说明AppRole分配没成功,重新执行PowerShell命令。 - WebAPI返回401 Unauthorized:检查请求头里的Authorization格式是不是
Bearer <Token>,Token有没有过期,或者资源参数和WebAPI的AAD应用的「受众」配置不匹配。
内容的提问来源于stack exchange,提问作者cty

