通过REST端点向Azure Application Insights发遥测的授权错误排查
关于Azure Application Insights遥测代理授权错误的排查与解决
当Azure Application Insights禁用本地身份验证后,前端无法直接上报遥测数据。为打通前后端日志链路,我在.NET Core API中实现了Telemetry Proxy Controller,但通过代理发送数据时收到Authorization not supported错误。
代理控制器代码
using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using Azure.Core; using Azure.Identity; using IdentityModel.Client; using Microsoft.ApplicationInsights; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; namespace Reporting.API.Controllers { [Route("api/[controller]")] [AllowAnonymous] [ApiController] public class TelemetryProxyController : ControllerBase { public TelemetryProxyController(IConfiguration configuration) { _client = new HttpClient(); _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); } private static readonly string _appInsightsEndpoint = "https://dc.services.visualstudio.com/v2/track"; private readonly HttpClient _client; private readonly IConfiguration _configuration; [HttpPost] public async Task Post(CancellationToken cancellationToken) { var credential = new DefaultAzureCredential(); var scope = "https://monitor.azure.com//.default"; var token = await credential.GetTokenAsync( new TokenRequestContext(new[] { scope }), cancellationToken ); var request = new HttpRequestMessage { RequestUri = new Uri(_appInsightsEndpoint), Method = HttpMethod.Post, Content = new StreamContent(Request.Body) }; foreach (var header in Request.Headers) { request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); var response = await _client.SendAsync(request, cancellationToken); using var streamReader = new StreamReader( await response.Content.ReadAsStreamAsync(cancellationToken) ); string result = await streamReader.ReadToEndAsync(); await Response.WriteAsync(result, cancellationToken: cancellationToken); } } }
遥测负载示例
[{"time":"2023-07-17T14:09:11.157Z","iKey":"00000000-0000-0000-0000-000000000000","name":"Microsoft.ApplicationInsights.2214063857374902a13cfbe145ee961c.Pageview","tags":{"ai.user.id":"XXXX","ai.session.id":"00000000-0000-0000-0000-000000000000","ai.device.id":"browser","ai.device.type":"Browser","ai.operation.name":"dashboard","ai.operation.id":"78bd3140ac724066a5d7ca41b78f5509","ai.internal.sdkVersion":"javascript:2.8.10","ai.internal.snippet":"-"},"data":{"baseType":"PageviewData","baseData":{"ver":2,"name":"next / dashboard","url":"https://next.ourcompany.nl/","duration":"00:00:00.623","properties":{"refUri":"","duration":"623"},"measurements":{},"id":"78bd3140ac724066a5d7ca41b78f5509"}}}]
错误响应
{"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Authorization not supported"}],"appId":"00000000-0000-0000-0000-000000000000"}
错误原因与解决方法
核心原因
你使用的传统遥测上报端点https://dc.services.visualstudio.com/v2/track仅支持基于Instrumentation Key(iKey)的身份验证,不兼容Azure AD令牌授权,即使令牌有效也会被端点拒绝。
解决步骤
切换到支持Azure AD的区域端点
替换原端点为对应区域的专用授权端点,格式为:https://<region>.in.applicationinsights.azure.com/v2/track例如西欧区域的端点为
https://westeurope.in.applicationinsights.azure.com/v2/track,可在Application Insights资源的"概述"页面获取对应区域地址。修正权限范围格式
原代码中scope多了一个斜杠,改为正确格式:var scope = "https://monitor.azure.com/.default";优化请求头部转发逻辑
避免转发前端所有头部导致冲突,仅保留必要的内容头部(如Content-Type):// 替换原头部循环逻辑 request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");可选:移除负载中的iKey
使用Azure AD授权时,iKey可省略,令牌会自动关联到对应资源;若保留iKey,需确保其与令牌关联的Application Insights资源一致。
修改后的核心代码片段
private static readonly string _appInsightsEndpoint = "https://westeurope.in.applicationinsights.azure.com/v2/track"; // 替换为你的区域端点 [HttpPost] public async Task Post(CancellationToken cancellationToken) { var credential = new DefaultAzureCredential(); var scope = "https://monitor.azure.com/.default"; // 修正scope格式 var token = await credential.GetTokenAsync( new TokenRequestContext(new[] { scope }), cancellationToken ); var request = new HttpRequestMessage { RequestUri = new Uri(_appInsightsEndpoint), Method = HttpMethod.Post, Content = new StreamContent(Request.Body) }; // 仅添加必要头部 request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); var response = await _client.SendAsync(request, cancellationToken); using var streamReader = new StreamReader( await response.Content.ReadAsStreamAsync(cancellationToken) ); string result = await streamReader.ReadToEndAsync(); await Response.WriteAsync(result, cancellationToken: cancellationToken); }
内容的提问来源于stack exchange,提问作者Joost
相关产品推荐
相关产品推荐

