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

.NET 6环境下Azure Functions v4如何实现Policy授权能力?

问题结论

运行在.NET 6环境下的Azure Functions v4完全可以实现和原ASP.NET Core Web App一致的基于Policy的授权逻辑,也可以通过自定义中间件达成该需求,原有权限管控相关的代码几乎可以无缝复用。

实现步骤(以隔离进程模型为例,进程内模型逻辑一致仅管道适配代码略有差异)
  • 第一步:安装所需依赖包
    需引入Microsoft.Azure.Functions.Worker、Microsoft.AspNetCore.Authentication.JwtBearer、Microsoft.AspNetCore.Authorization等NuGet包。
  • 第二步:复用原有授权配置注册服务
    在Program.cs中直接复制原Web App的身份验证、授权服务注册逻辑,包括JWT参数配置、Policy规则定义:
    var host = new HostBuilder()
        .ConfigureServices(services => 
        {
            // 复用原Web App的JWT验证配置
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options => 
                {
                    options.Authority = "你的JWT签发地址";
                    options.Audience = "你的接口受众标识";
                    // 其余验证配置完全复用原有代码
                });
            // 复用原Web App的Policy定义
            services.AddAuthorization(options =>
            {
                options.AddPolicy(Permissions.Announcements.Edit, policy => 
                    policy.RequireClaim("Permission", Permissions.Announcements.Edit));
                // 其余Policy直接迁移即可
            });
        })
        .ConfigureFunctionsWorkerDefaults(app => 
        {
            // 注册自定义授权中间件
            app.UseMiddleware<JwtAuthorizationMiddleware>();
        })
        .Build();
    
    host.Run();
    
  • 第三步:编写自定义授权中间件
    中间件负责解析JWT、验证身份、调用原生授权服务校验Policy:
    public class JwtAuthorizationMiddleware : IFunctionsWorkerMiddleware
    {
        private readonly IAuthorizationService _authorizationService;
        private readonly IJwtSecurityTokenHandler _jwtHandler;
    
        public JwtAuthorizationMiddleware(IAuthorizationService authorizationService, IJwtSecurityTokenHandler jwtHandler)
        {
            _authorizationService = authorizationService;
            _jwtHandler = jwtHandler;
        }
    
        public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
        {
            var httpReq = await context.GetHttpRequestDataAsync();
            if (httpReq == null) 
            {
                await next(context);
                return;
            }
    
            // 解析请求头的JWT令牌
            if (!httpReq.Headers.TryGetValues("Authorization", out var authHeaders) || 
                !authHeaders.FirstOrDefault()?.StartsWith("Bearer ") == true)
            {
                var unAuthorizedRes = httpReq.CreateResponse(HttpStatusCode.Unauthorized);
                context.GetInvocationResult().Value = unAuthorizedRes;
                return;
            }
            var token = authHeaders.First().Substring("Bearer ".Length).Trim();
    
            // 验证JWT有效性,生成ClaimsPrincipal,逻辑复用原Web App代码
            ClaimsPrincipal principal;
            try
            {
                principal = _jwtHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidIssuer = "你的JWT签发地址",
                    ValidateAudience = true,
                    ValidAudience = "你的接口受众标识",
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的签名密钥"))
                }, out _);
            }
            catch
            {
                var unAuthorizedRes = httpReq.CreateResponse(HttpStatusCode.Unauthorized);
                context.GetInvocationResult().Value = unAuthorizedRes;
                return;
            }
    
            // 读取当前Function绑定的Authorize特性,获取Policy名称
            var targetMethod = context.GetTargetFunctionMethod();
            var authorizeAttr = targetMethod.GetCustomAttribute<AuthorizeAttribute>();
            if (authorizeAttr != null && !string.IsNullOrEmpty(authorizeAttr.Policy))
            {
                // 调用ASP.NET Core原生授权服务校验Policy,和原Web App逻辑完全一致
                var authResult = await _authorizationService.AuthorizeAsync(principal, authorizeAttr.Policy);
                if (!authResult.Succeeded)
                {
                    var forbiddenRes = httpReq.CreateResponse(HttpStatusCode.Forbidden);
                    context.GetInvocationResult().Value = forbiddenRes;
                    return;
                }
            }
    
            // 校验通过,将用户身份存入上下文供业务代码调用
            context.Items["CurrentUser"] = principal;
            await next(context);
        }
    }
    
  • 第四步:业务代码适配
    原有业务逻辑几乎不用改动,只需要给Function方法加上Azure Functions的Http触发配置,注意Http触发的授权级别设置为Anonymous,因为我们已经自定义了JWT授权逻辑:
    [Function("MyFunction")]
    [Authorize(Policy = Permissions.Announcements.Edit)]
    public HttpResponseData MyFunction(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "myfunction")] HttpRequestData req, 
        [FromBody] MyDTO dto, 
        FunctionContext context)
    {
        // 从上下文获取当前用户身份,和原Web App的User对象用法一致
        var currentUser = context.Items["CurrentUser"] as ClaimsPrincipal;
        /* 原业务代码直接复用 */
    }
    
注意事项
  • 如果你使用的是进程内托管模型,只需要把中间件替换为Azure Functions的Filter实现即可,核心的JWT验证、Policy校验逻辑完全不用改动。
  • 原有的ASP.NET Core Identity相关的服务注册、权限判断逻辑可以直接迁移,无需重构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:24:02