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

Azure Functions(.NET8独立模式)OIDC请求Header中Access Token验证咨询

.NET 8 Azure Functions JWT 验证实现方案

推荐方案:使用内置认证中间件(基于Microsoft.Identity.Web)

这种方式无需自定义中间件,借助官方包即可快速实现OpenID Connect兼容的JWT验证,自动处理JWKS获取、签名校验、受众/发行人验证等逻辑。

步骤1:安装依赖包

通过NuGet安装以下包:

Microsoft.Azure.Functions.Worker.Extensions.Http
Microsoft.Identity.Web
Microsoft.Azure.Functions.Worker

步骤2:配置认证参数

在appsettings.json中添加OIDC提供商(以Azure AD为例)的配置:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "你的租户ID",
    "ClientId": "你的应用ID"
  },
  "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}

步骤3:配置服务与中间件

在Program.cs中注册认证和授权服务:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        // 注册JWT认证服务,绑定OIDC配置
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
        
        // 启用授权
        services.AddAuthorization();
    })
    .Build();

host.Run();

步骤4:保护你的函数

在Get函数上添加[Authorize]特性,同时将HttpTrigger的授权级别设为Anonymous(避免Azure Functions内置密钥验证冲突):

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace YourFunctionNamespace;

public class ProtectedRouteFunction
{
    private readonly ILogger<ProtectedRouteFunction> _logger;

    public ProtectedRouteFunction(ILogger<ProtectedRouteFunction> logger)
    {
        _logger = logger;
    }

    [Function("ProtectedRoute")]
    [Authorize]
    public IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
    {
        _logger.LogInformation("处理受保护的请求");
        return new OkObjectResult("Protected Route, 200");
    }
}

自定义授权策略(可选)

如果需要验证特定Claim(比如权限范围),可以添加自定义策略:

// 在Program.cs的ConfigureServices中
services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAccessScope", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireClaim("scope", "api://你的应用ID/access_as_user");
    });
});

// 函数上使用自定义策略
[Authorize(Policy = "RequireAccessScope")]

自定义中间件方案(若需完全自定义验证逻辑)

如果一定要手动实现JWT验证中间件,可参考以下代码:

自定义中间件类

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

public class JwtValidationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;
    private readonly ILogger<JwtValidationMiddleware> _logger;
    private readonly IConfigurationManager<OpenIdConnectConfiguration> _configManager;

    public JwtValidationMiddleware(RequestDelegate next, IConfiguration configuration, ILogger<JwtValidationMiddleware> logger)
    {
        _next = next;
        _configuration = configuration;
        _logger = logger;

        // 初始化OIDC配置管理器,自动获取JWKS
        var metadataAddress = $"{_configuration["AzureAd:Instance"]}{_configuration["AzureAd:TenantId"]}/v2.0/.well-known/openid-configuration";
        _configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
            metadataAddress,
            new OpenIdConnectConfigurationRetriever(),
            new HttpDocumentRetriever());
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 检查Authorization Header
        if (!context.Request.Headers.TryGetValue("Authorization", out var authHeader))
        {
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            await context.Response.WriteAsync("缺少Authorization请求头");
            return;
        }

        var token = authHeader.ToString().Replace("Bearer ", string.Empty);
        try
        {
            // 获取最新的OIDC配置(含JWKS)
            var oidcConfig = await _configManager.GetConfigurationAsync(CancellationToken.None);
            var validationParams = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = oidcConfig.Issuer,
                ValidateAudience = true,
                ValidAudience = _configuration["AzureAd:ClientId"],
                ValidateLifetime = true,
                IssuerSigningKeys = oidcConfig.SigningKeys
            };

            // 验证Token
            var handler = new JwtSecurityTokenHandler();
            handler.ValidateToken(token, validationParams, out var validatedToken);

            // 将验证后的Claims绑定到HttpContext
            context.User = new ClaimsPrincipal(new ClaimsIdentity(((JwtSecurityToken)validatedToken).Claims, "JWT"));

            // 继续处理请求
            await _next(context);
        }
        catch (SecurityTokenException ex)
        {
            _logger.LogError(ex, "JWT验证失败");
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            await context.Response.WriteAsync($"无效Token: {ex.Message}");
        }
    }
}

注册中间件

在Program.cs中添加中间件注册:

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication(app =>
    {
        // 注册自定义JWT验证中间件
        app.UseMiddleware<JwtValidationMiddleware>();
    })
    .ConfigureServices(services =>
    {
        // 其他服务配置
    })
    .Build();

host.Run();

内容的提问来源于stack exchange,提问作者Luan Souza - Dev LuanS0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 02:49:56