.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
相关产品推荐
相关产品推荐

