如何在Azure Function的Startup类中使用中间件解密HTTP请求?解决IFunctionsHostBuilder无UseMiddleware方法问题
Hey there! I totally get the confusion here—Azure Functions doesn’t have that straightforward UseMiddleware method like ASP.NET Core does, but there are still solid ways to add your request decryption logic into the pipeline. Let’s break down the two main approaches depending on your Functions hosting model:
Option 1: Use Function Invocation Filters (Works for All Function Types)
This approach works for both In-Process and Isolated Worker models, and applies to every function in your app (not just HTTP-triggered ones). It’s great for cross-cutting logic like request decryption.
Step 1: Create a Decryption Filter
Implement the IFunctionInvocationFilter interface to handle the decryption logic before your function runs:
using Microsoft.Azure.WebJobs.Host; using System.IO; using System.Threading; using System.Threading.Tasks; public class DecryptionFilter : IFunctionInvocationFilter { // Runs BEFORE your function executes public async Task OnExecutingAsync(FunctionExecutingContext context, CancellationToken cancellationToken) { // Target HTTP requests by looking for the "req" argument (default name for HTTP triggers) if (context.Arguments.TryGetValue("req", out var reqObj) && reqObj is HttpRequest req) { // Read and decrypt the request body var decryptedStream = await DecryptRequestStream(req.Body); // Reset the stream position so subsequent code can read it decryptedStream.Position = 0; req.Body = decryptedStream; } } // Runs AFTER your function executes (optional, skip if you don't need post-processing) public Task OnExecutedAsync(FunctionExecutedContext context, CancellationToken cancellationToken) { return Task.CompletedTask; } private async Task<Stream> DecryptRequestStream(Stream encryptedStream) { // Replace this with your actual decryption logic // Example: Read encrypted content, decrypt it, return a new stream with decrypted data var memoryStream = new MemoryStream(); await encryptedStream.CopyToAsync(memoryStream); // Simulate decryption (replace with your real code) var decryptedBytes = System.Text.Encoding.UTF8.GetBytes( System.Text.Encoding.UTF8.GetString(memoryStream.ToArray()) ); return new MemoryStream(decryptedBytes); } }
Step 2: Register the Filter in Startup.cs
Update your existing Startup class to register the filter as a singleton service:
using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using System; [assembly: FunctionsStartup(typeof(YourAppNamespace.Startup))] namespace YourAppNamespace { public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { if (builder == null) throw new ArgumentNullException(nameof(builder), "Host builder cannot be null."); // Register your decryption filter builder.Services.AddSingleton<IFunctionInvocationFilter, DecryptionFilter>(); } } }
Option 2: ASP.NET Core Middleware (Isolated Worker Model Only)
If you’re using the Isolated Worker Model (recommended for newer projects), you can integrate ASP.NET Core-style middleware directly into the HTTP pipeline. This is more familiar if you’re used to ASP.NET Core development.
Step 1: Configure Middleware in Program.cs
Isolated Worker projects use Program.cs instead of Startup.cs. Add your middleware to the functions worker pipeline:
using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Hosting; var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults(builder => { // Add your custom decryption middleware builder.UseMiddleware<DecryptionMiddleware>(); }) .Build(); host.Run();
Step 2: Implement the Decryption Middleware
Create a class that implements IFunctionsWorkerMiddleware:
using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Azure.Functions.Worker.Middleware; using System.IO; using System.Threading.Tasks; public class DecryptionMiddleware : IFunctionsWorkerMiddleware { public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { // Access the HTTP request from the function context if (context.BindingContext.BindingData.TryGetValue("HttpRequest", out var reqObj) && reqObj is HttpRequestData req) { // Read encrypted body content var encryptedContent = await req.ReadAsStringAsync(); // Decrypt the content (replace with your logic) var decryptedContent = DecryptContent(encryptedContent); // Create a new request with the decrypted body var updatedRequest = req.CreateRequest(req.Url); updatedRequest.Body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(decryptedContent)); // Replace the original request in the context context.Items["HttpRequest"] = updatedRequest; } // Pass control to the next middleware/function await next(context); } private string DecryptContent(string encryptedText) { // Replace this with your actual decryption logic return encryptedText; // Example placeholder } }
Key Notes to Remember
- Stream Position: Always reset the stream position after reading it (like
decryptedStream.Position = 0)—otherwise, subsequent code won’t be able to read the request body. - Model Compatibility: Function Filters work for both models, but ASP.NET Core middleware only works with the Isolated Worker Model. Double-check which model your project uses.
内容的提问来源于stack exchange,提问作者user2135647

