使用PowerShell携带OAuth Token调用Azure HTTP函数遇401未授权
问题描述
我有一个运行在GCCH环境下、启用了身份验证的Azure Function,配置细节如下:
- App Service身份验证已启用,访问限制设为需身份验证,未授权请求返回HTTP 401
- 令牌存储已开启
- 身份提供商指定为某特定Client ID的应用
目前Power Automate向该HTTP函数发送POST请求可正常执行,但通过桌面PowerShell获取OAuth Token后调用时,无论URL是否携带code参数,均返回401未授权。相关PowerShell代码如下:
#These URLs are used to access get the token; scope has not been required is uses the app ID $loginURL = "https://login.microsoftonline.us" $resource = "https://graph.microsoft.us" $Tenant = "mytenant.onmicrosoft.us" $ClientID = "removed" $Secret="removed" $fcnKey = "removed" $fcnURL = "https://removed?" #Azure function url without the code at the end $AuthBody = @{ grant_type="client_credentials"; resource=$resource; client_id=$ClientID; client_secret=$Secret} $Oauth = Invoke-RestMethod -Method POST -Uri $loginURL/$Tenant/oauth2/token?api-version=1.0 -Body $AuthBody -ContentType "application/x-www-form-urlencoded" $AuthToken = @{ 'Authorization'="$($Oauth.token_type) $($Oauth.access_token)"; 'Content-Type' = "application/json"; 'x-functions-key' = $fcnkey;} #This returns a 401 unauthorized Invoke-RestMethod -Headers $AuthToken -Uri $fcnURL -Method POST #This also returns a 401 unauthorized $AuthToken = @{ 'Authorization'="$($Oauth.token_type) $($Oauth.access_token)"; 'Content-Type' = "application/json";} $FullURL = "https://removed?code=removed" Invoke-RestMethod -Headers $AuthToken -Uri $fullURL -Method POST
排查与解决步骤
1. 修正Token请求的Resource参数
当前代码中resource用的是Graph API地址https://graph.microsoft.us,但Azure Function的身份验证需要验证函数自身的受众(Audience),而非Graph API。
- 将
$resource替换为你的Azure Function应用的Client ID,或者函数的完整URL(例如https://your-function-name.azurewebsites.us),重新获取Token。
2. 验证Token的核心字段有效性
获取Token后,通过本地JWT解码工具检查以下字段:
aud(受众)必须与Azure Function的Client ID或应用URL完全匹配iss(颁发者)必须是GCCH环境的合法地址,例如https://login.microsoftonline.us/{租户ID}/v2.0
若字段不匹配,说明Resource参数错误,Token无法被函数的身份验证逻辑认可。
3. 避免同时使用两种认证凭证
Azure Function的认证机制为二选一:要么用OAuth Token(Authorization头),要么用函数密钥(x-functions-key头或URL中的code参数)。同时传递两种凭证会触发验证冲突,导致401错误。
- 仅保留其中一种认证方式即可。
4. 确认应用权限配置
检查用于获取Token的应用(指定Client ID)是否被授权访问目标Azure Function:
- 在GCCH版Azure Portal中,进入函数的App Service身份验证设置,确认该应用已被添加为允许的客户端
- 确保该应用的服务主体在函数的IAM权限中拥有合适角色(如
Function App Contributor)
5. 修复PowerShell代码语法错误
原代码中获取Token的Invoke-RestMethod存在语法断行问题,会导致Token获取失败:
# 错误写法 $Oauth = Invoke-RestMethod -Method POST -Uri $loginURL/$Tenant/oauth2/token?api-version=1.0 -Body $AuthBody -ContentType "application/x-www-form-urlencoded"
修正为:
# 正确写法 $Oauth = Invoke-RestMethod -Method POST -Uri "$loginURL/$Tenant/oauth2/token?api-version=1.0" -Body $AuthBody -ContentType "application/x-www-form-urlencoded"
6. 适配GCCH环境的OAuth端点
若函数使用v2.0身份验证,建议改用v2.0的Token端点,同时将scope参数设置为{函数Client ID}/.default(替换原resource参数),示例:
$AuthBody = @{ grant_type = "client_credentials"; scope = "{function-client-id}/.default"; client_id = $ClientID; client_secret = $Secret } $Oauth = Invoke-RestMethod -Method POST -Uri "$loginURL/$Tenant/oauth2/v2.0/token" -Body $AuthBody -ContentType "application/x-www-form-urlencoded"
修正后的完整示例代码
# GCCH环境配置 $loginURL = "https://login.microsoftonline.us" # 替换为你的Azure Function的Client ID或应用URL $resource = "your-function-app-client-id" $Tenant = "mytenant.onmicrosoft.us" $ClientID = "removed" $Secret = "removed" $fcnURL = "https://removed" # 移除末尾多余的? # 获取Token(修正语法与Resource参数) $AuthBody = @{ grant_type = "client_credentials"; resource = $resource; client_id = $ClientID; client_secret = $Secret } $Oauth = Invoke-RestMethod -Method POST -Uri "$loginURL/$Tenant/oauth2/token?api-version=1.0" -Body $AuthBody -ContentType "application/x-www-form-urlencoded" # 仅使用OAuth Token认证 $AuthToken = @{ 'Authorization' = "$($Oauth.token_type) $($Oauth.access_token)"; 'Content-Type' = "application/json"; } # 调用Azure Function Invoke-RestMethod -Headers $AuthToken -Uri $fcnURL -Method POST
内容的提问来源于stack exchange,提问作者FlorH
相关产品推荐
相关产品推荐

