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

