如何在Azure隔离式函数中获取HttpClient传递的NetworkCredential认证信息
解决Azure隔离式函数处理Basic Auth凭证的方案
核心思路
Azure隔离式函数不会自动解析NetworkCredential对应的Basic Auth凭证,需要手动从请求头中提取并校验,无需额外安装NuGet包,只需调整函数配置并编写自定义校验逻辑。
步骤1:调整函数授权级别
将函数的授权级别设为Anonymous,避免Azure函数自带的授权拦截请求,让请求能进入自定义校验流程:
- 在函数代码的
HttpTrigger属性中指定:[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] - 或在
function.json中配置(如果用文件驱动的函数):{ "authLevel": "anonymous", // 其他配置... }
步骤2:解析并校验Basic Auth凭证
从HttpRequestData的Authorization请求头中提取用户名和密码,完成校验后再处理业务逻辑:
[Function("MyApiFunction")] public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req) { // 1. 检查Authorization头是否存在 if (!req.Headers.TryGetValues("Authorization", out var authHeaders) || !authHeaders.Any()) { var unauthorizedResp = req.CreateResponse(HttpStatusCode.Unauthorized); unauthorizedResp.Headers.Add("WWW-Authenticate", "Basic realm=\"MyFunctionRealm\""); return unauthorizedResp; } var authHeader = authHeaders.First(); // 2. 验证是否为Basic Auth scheme if (!authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase)) { var badResp = req.CreateResponse(HttpStatusCode.BadRequest); await badResp.WriteStringAsync("仅支持Basic认证方案"); return badResp; } // 3. 解码凭证 var base64Credentials = authHeader["Basic ".Length..].Trim(); var credentialsBytes = Convert.FromBase64String(base64Credentials); var credentials = Encoding.UTF8.GetString(credentialsBytes).Split(':', 2); if (credentials.Length != 2) { var badResp = req.CreateResponse(HttpStatusCode.BadRequest); await badResp.WriteStringAsync("凭证格式无效"); return badResp; } var username = credentials[0]; var password = credentials[1]; // 4. 校验凭证(从环境变量/Key Vault读取合法凭证,避免硬编码) var validUsername = Environment.GetEnvironmentVariable("VALID_USERNAME"); var validPassword = Environment.GetEnvironmentVariable("VALID_PASSWORD"); if (username != validUsername || password != validPassword) { var unauthorizedResp = req.CreateResponse(HttpStatusCode.Unauthorized); unauthorizedResp.Headers.Add("WWW-Authenticate", "Basic realm=\"MyFunctionRealm\""); return unauthorizedResp; } // 5. 校验通过,执行业务逻辑 var response = req.CreateResponse(HttpStatusCode.OK); await response.WriteStringAsync("认证通过,业务处理完成"); return response; }
步骤3:安全存储合法凭证
将合法的用户名和密码存储在Azure函数的应用程序设置中(避免硬编码),如果需要更高安全性,可将凭证存入Azure Key Vault,通过函数的系统托管身份访问Key Vault,再通过应用程序设置引用Key Vault秘密。
可选:用中间件统一处理多函数认证
如果多个函数都需要Basic Auth校验,可编写自定义中间件实现统一处理:
public class BasicAuthMiddleware : IFunctionsWorkerMiddleware { public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { var req = await context.GetHttpRequestDataAsync(); if (req == null) { await next(context); return; } bool isAuthorized = false; try { if (req.Headers.TryGetValues("Authorization", out var authHeaders) && authHeaders.Any()) { var authHeader = authHeaders.First(); if (authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase)) { var base64Credentials = authHeader["Basic ".Length..].Trim(); var credentialsBytes = Convert.FromBase64String(base64Credentials); var credentials = Encoding.UTF8.GetString(credentialsBytes).Split(':', 2); if (credentials.Length == 2) { var validUsername = Environment.GetEnvironmentVariable("VALID_USERNAME"); var validPassword = Environment.GetEnvironmentVariable("VALID_PASSWORD"); isAuthorized = credentials[0] == validUsername && credentials[1] == validPassword; } } } } catch { isAuthorized = false; } if (!isAuthorized) { var unauthorizedResp = req.CreateResponse(HttpStatusCode.Unauthorized); unauthorizedResp.Headers.Add("WWW-Authenticate", "Basic realm=\"MyFunctionRealm\""); await context.GetInvocationResultAsync().SetResult(unauthorizedResp); return; } await next(context); } }
在Program.cs中注册中间件:
var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults(builder => { builder.UseMiddleware<BasicAuthMiddleware>(); }) .Build(); host.Run();
内容的提问来源于stack exchange,提问作者Marcos
相关产品推荐
相关产品推荐

