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

Azure Functions v4(.NET 7隔离进程)自定义授权新实现方式咨询

在Azure Functions v4 .NET 7隔离进程中实现自定义授权的新方式

在Azure Functions v4的隔离进程模式下,旧的FunctionInvocationFilterAttribute及FunctionExecutingContext已被标记为过时,官方推荐使用**Functions Worker Middleware(函数工作者中间件)**来处理自定义授权这类横切逻辑。以下是具体实现步骤和示例:

一、全局授权中间件实现

1. 创建自定义授权中间件类

实现IFunctionsWorkerMiddleware接口,在InvokeAsync方法中编写授权逻辑:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;
using System.Net;
using System.Security.Claims;
using System.Linq;

public class CustomAuthorizationMiddleware : IFunctionsWorkerMiddleware
{
    public async Task InvokeAsync(FunctionContext context, FunctionExecutionDelegate next)
    {
        // 仅针对HTTP触发的函数处理授权(非HTTP触发可按需调整逻辑)
        var reqData = await context.GetHttpRequestDataAsync();
        if (reqData == null)
        {
            await next(context);
            return;
        }

        // 1. 提取授权头
        var authHeader = reqData.Headers.TryGetValues("Authorization", out var values) 
            ? values.FirstOrDefault() 
            : null;
        
        if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
        {
            var response = reqData.CreateResponse(HttpStatusCode.Unauthorized);
            await response.WriteStringAsync("缺少或无效的授权头");
            return;
        }

        // 2. 验证Token(替换为实际的Token校验逻辑,比如JWT解析)
        var token = authHeader.Substring("Bearer ".Length);
        if (!ValidateToken(token))
        {
            var response = reqData.CreateResponse(HttpStatusCode.Unauthorized);
            await response.WriteStringAsync("无效的Token");
            return;
        }

        // 3. 验证通过后,将用户信息注入上下文
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, "user_123"),
            new Claim(ClaimTypes.Role, "Admin")
        };
        context.Items["ClaimsPrincipal"] = new ClaimsPrincipal(new ClaimsIdentity(claims, "CustomAuth"));

        // 4. 继续执行后续中间件和函数逻辑
        await next(context);
    }

    // 示例Token验证方法,实际需替换为业务逻辑
    private bool ValidateToken(string token)
    {
        return token == "your-valid-token-here";
    }
}

2. 注册中间件

在Program.cs中配置函数主机时,添加自定义中间件:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(builder =>
    {
        // 注册自定义授权中间件(全局生效)
        builder.UseMiddleware<CustomAuthorizationMiddleware>();
    })
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
    })
    .Build();

host.Run();

二、按需授权(针对特定函数应用)

如果不需要全局授权,可通过自定义属性标记需要保护的函数,再在中间件中判断是否执行授权逻辑:

1. 创建自定义授权属性

[AttributeUsage(AttributeTargets.Method)]
public class CustomAuthorizeAttribute : Attribute
{
    // 可添加角色参数,实现基于角色的授权
    public string[] RequiredRoles { get; set; } = Array.Empty<string>();
}

2. 在函数上标记属性

public class ProtectedFunctions
{
    // 需要授权的函数
    [Function("AdminOnlyFunction")]
    [CustomAuthorize(RequiredRoles = new[] { "Admin" })]
    public HttpResponseData AdminFunction([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.WriteString("仅管理员可访问");
        return response;
    }

    // 无需授权的公开函数
    [Function("PublicFunction")]
    public HttpResponseData PublicFunction([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.WriteString("公开访问");
        return response;
    }
}

3. 修改中间件适配按需授权

public async Task InvokeAsync(FunctionContext context, FunctionExecutionDelegate next)
{
    // 获取当前函数的属性标记
    var authorizeAttr = context.FunctionDefinition
        .GetCustomAttributes<CustomAuthorizeAttribute>()
        .FirstOrDefault();

    // 无授权标记则直接放行
    if (authorizeAttr == null)
    {
        await next(context);
        return;
    }

    // 以下为授权逻辑(同全局中间件,额外增加角色校验)
    var reqData = await context.GetHttpRequestDataAsync();
    if (reqData == null)
    {
        await next(context);
        return;
    }

    var authHeader = reqData.Headers.TryGetValues("Authorization", out var values) 
        ? values.FirstOrDefault() 
        : null;
    
    if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
    {
        var response = reqData.CreateResponse(HttpStatusCode.Unauthorized);
        await response.WriteStringAsync("缺少或无效的授权头");
        return;
    }

    var token = authHeader.Substring("Bearer ".Length);
    if (!ValidateToken(token))
    {
        var response = reqData.CreateResponse(HttpStatusCode.Unauthorized);
        await response.WriteStringAsync("无效的Token");
        return;
    }

    // 角色校验(如果属性指定了角色)
    var claimsPrincipal = context.Items["ClaimsPrincipal"] as ClaimsPrincipal;
    if (authorizeAttr.RequiredRoles.Any() && 
        (claimsPrincipal == null || !authorizeAttr.RequiredRoles.Any(r => claimsPrincipal.IsInRole(r))))
    {
        var response = reqData.CreateResponse(HttpStatusCode.Forbidden);
        await response.WriteStringAsync("权限不足");
        return;
    }

    await next(context);
}

关键说明

  • 隔离进程模式下,中间件是处理横切逻辑的标准方式,替代了旧版过滤器
  • 非HTTP触发的函数(如队列、定时器),需根据触发源的特性调整授权逻辑(比如校验队列消息的元数据签名)
  • 实际项目中,建议使用System.IdentityModel.Tokens.Jwt库实现标准JWT解析和验证,替代示例中的简单Token校验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:25:36