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

如何使用Azure Authentication保护代码优先的gRPC端点?

解决方案:用Azure JWT保护protobuf-net.Grpc端点

一、服务器端配置排查与修正

1. 确保protobuf-net.Grpc服务注册

在Program.cs中添加代码优先gRPC服务的注册:

builder.Services.AddCodeFirstGrpc();

2. 修正中间件管道顺序

gRPC认证依赖正确的中间件顺序,必须保证UseAuthentication和UseAuthorization在UseRouting之后、UseEndpoints之前:

app.UseRouting();

// 认证授权中间件必须放在此处
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers(); // 保留原REST端点映射
    endpoints.MapGrpcService<ServerGreeterService>(); // 映射你的gRPC服务
    // 可选:添加反射服务方便客户端生成代码
    endpoints.MapCodeFirstGrpcReflectionService();
});

3. 优化JWT令牌检索配置

显式配置JWTBearer的令牌检索逻辑,确保能从gRPC元数据(HTTP/2头)中正确读取令牌:

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(options =>
    {
        builder.Configuration.Bind("Authorization:AzureAd", options);
        options.UseSecurityTokenValidators = true;
        
        // 显式指定令牌检索规则,兼容gRPC元数据传递
        options.TokenRetriever = request =>
        {
            // 优先从Authorization头获取
            var token = TokenRetrieval.FromAuthorizationHeader()(request);
            if (string.IsNullOrEmpty(token))
            {
                // 可选:支持从查询参数获取(gRPC场景一般不需要)
                token = TokenRetrieval.FromQueryString()(request);
            }
            return token;
        };
    },
    options =>
    {
        builder.Configuration.Bind("Authorization:AzureAd", options);
    });

4. 验证Azure AD配置匹配

检查服务器端appsettings.json中的Authorization:AzureAd配置,确保Audience与客户端获取的JWT令牌的aud声明完全一致:

"Authorization": {
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "你的租户ID",
    "ClientId": "你的服务器应用ID",
    "Audience": "api://你的服务器应用ID" // 必须与JWT的aud声明匹配
  }
}

可以用jwt.io解析客户端获取的令牌,确认aud、iss等声明符合服务器配置要求。

二、客户端配置修正

1. 注册HttpContextAccessor

客户端代码依赖IHttpContextAccessor获取当前请求的令牌,需在客户端Program.cs中添加注册:

builder.Services.AddHttpContextAccessor();

2. 验证令牌传递逻辑

确保客户端传递的Authorization头格式正确,避免重复添加Bearer前缀:

.AddCallCredentials((context, metadata, serviceProvider) =>
{
    var httpContext = serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
    if (httpContext != null && httpContext.Request.Headers.TryGetValue("Authorization", out var authHeader))
    {
        // 直接使用原始头值,避免拆分后重复添加Bearer
        metadata.Add("Authorization", authHeader.ToString());
    }
    return Task.CompletedTask;
});

三、调试排查方法

1. 服务器端查看请求头

添加中间件打印接收到的元数据,确认Authorization头是否正确传递:

// 放在UseAuthentication之前
app.Use(async (context, next) =>
{
    if (context.Request.Headers.ContainsKey("Authorization"))
    {
        Console.WriteLine($"Received Authorization: {context.Request.Headers["Authorization"]}");
    }
    await next();
});

2. 客户端验证元数据发送

在客户端AddCallCredentials中添加日志,确认令牌已正确添加到元数据:

.AddCallCredentials((context, metadata, serviceProvider) =>
{
    var httpContext = serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
    if (httpContext != null && httpContext.Request.Headers.TryGetValue("Authorization", out var authHeader))
    {
        metadata.Add("Authorization", authHeader.ToString());
        Console.WriteLine($"Sent Authorization: {authHeader}");
    }
    return Task.CompletedTask;
});

内容的提问来源于stack exchange,提问作者M. Ozn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:50:09