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

使用Azure资源管理API创建Service Bus混合连接的授权问题

解决Azure管理API创建Hybrid Connection时的401 AuthenticationFailedInvalidHeader错误

核心问题诊断

你遇到的401错误根源有两个:

  • 认证机制不匹配:你生成的是Relay服务专用的SharedAccessSignature令牌,但Azure资源管理(ARM)API只接受Azure Active Directory(AAD)颁发的Bearer令牌,这两种认证格式完全不兼容,所以会提示Authorization header格式无效。
  • HTTP请求方法错误:你用GetAsync来调用创建Hybrid Connection的端点,但ARM API中创建/更新资源需要使用PUT请求,GET仅用于查询已存在的资源。

修正方案步骤

1. 获取AAD Bearer令牌

调用ARM API必须通过AAD获取合法的Bearer令牌,推荐使用服务主体(Service Principal)来实现非交互式认证,步骤如下:

  • 在Azure AD中注册一个应用程序(服务主体)
  • 给该服务主体分配Relay Contributor或更高权限的角色到目标资源组/命名空间
  • 记录服务主体的客户端ID、客户端密钥、租户ID

你可以通过两种方式获取令牌:

方式一:使用MSAL库(推荐,简化流程)

安装Microsoft.Identity.Client NuGet包,然后用以下代码获取令牌:

public static async Task<string> GetArmAccessToken(string tenantId, string clientId, string clientSecret)
{
    var authority = $"https://login.microsoftonline.com/{tenantId}";
    var scopes = new[] { "https://management.azure.com/.default" };
    
    var app = ConfidentialClientApplicationBuilder
        .Create(clientId)
        .WithClientSecret(clientSecret)
        .WithAuthority(new Uri(authority))
        .Build();
    
    var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
    return result.AccessToken;
}
方式二:手动调用AAD REST端点(纯REST方式)

如果不想用SDK,可以直接发送POST请求到AAD令牌端点:

public static async Task<string> GetArmAccessTokenViaRest(string tenantId, string clientId, string clientSecret)
{
    var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
    var requestBody = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        { "grant_type", "client_credentials" },
        { "client_id", clientId },
        { "client_secret", clientSecret },
        { "scope", "https://management.azure.com/.default" }
    });
    
    using var httpClient = new HttpClient();
    var response = await httpClient.PostAsync(tokenEndpoint, requestBody);
    response.EnsureSuccessStatusCode();
    
    var tokenData = await response.Content.ReadFromJsonAsync<Dictionary<string, string>>();
    return tokenData["access_token"];
}

2. 修正HTTP请求方法和请求体

创建Hybrid Connection需要发送PUT请求,并携带符合ARM API要求的JSON请求体,示例请求体如下:

{
    "properties": {
        "requiresClientAuthorization": true,
        "userMetadata": "Test Hybrid Connection"
    },
    "location": "eastus" // 必须和Relay命名空间的区域一致
}

完整修正后的代码示例

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

namespace HybridConnectionManagement
{
    class Program
    {
        // ARM API相关配置
        private static string TenantId = "[your-tenant-id]";
        private static string ClientId = "[your-service-principal-client-id]";
        private static string ClientSecret = "[your-service-principal-client-secret]";
        
        static async Task Main(string[] args)
        {
            var createHybridConnectionEndpoint = "https://management.azure.com" +
                "/subscriptions/[subscription_id]" +
                "/resourceGroups/[resourceGroup]" +
                "/providers/Microsoft.Relay" +
                "/namespaces/[namespace]" +
                "/hybridConnections/test-521?api-version=2017-04-1";

            // 获取ARM API的Bearer令牌
            var accessToken = await GetArmAccessToken(TenantId, ClientId, ClientSecret);

            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = 
                    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
                httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");

                // 构造请求体
                var requestBody = new
                {
                    properties = new
                    {
                        requiresClientAuthorization = true,
                        userMetadata = "Created via ARM API"
                    },
                    location = "eastus" // 替换为你的Relay命名空间区域
                };

                // 发送PUT请求创建Hybrid Connection
                var response = await httpClient.PutAsJsonAsync(createHybridConnectionEndpoint, requestBody);
                var responseText = await response.Content.ReadAsStringAsync();

                Console.WriteLine(responseText);
            }
        }

        public static async Task<string> GetArmAccessToken(string tenantId, string clientId, string clientSecret)
        {
            var authority = $"https://login.microsoftonline.com/{tenantId}";
            var scopes = new[] { "https://management.azure.com/.default" };
            
            var app = ConfidentialClientApplicationBuilder
                .Create(clientId)
                .WithClientSecret(clientSecret)
                .WithAuthority(new Uri(authority))
                .Build();
            
            var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
            return result.AccessToken;
        }
    }
}

额外注意事项

  • 确保服务主体的权限足够:至少需要Relay Contributor角色,否则会返回403权限不足错误。
  • 请求体中的location必须和Relay命名空间的区域完全一致(比如eastus、westeurope等)。
  • ARM API的版本号可以根据需要调整,2017-04-1是稳定可用的版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:30:11