【问题标题】:How to create OWIN middleware per request如何根据请求创建 OWIN 中间件
【发布时间】:2026-01-28 18:10:01
【问题描述】:

我正在实现一个自定义 owin 中间件,以在响应标头中添加 CSP 标头(内容安全策略)。要使CSP 正常工作,中间件需要为每个请求创建一个唯一的 nonce 值。所以我有NonceService,它创造了随机值。自定义 OWIN 中间件依赖于 NonceService。

但是我的问题是我无法为每个请求注册自定义中间件。

当我调试时,我注意到 OWIN 为每个请求创建自定义中间件的新实例,因为所有请求都使用相同的 nonce 值。

下面是我的代码

Nonce 服务

public interface INonceService
{
    string GetNonce();
}

public class NonceService : INonceService
{
     private static readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
    private readonly string _nonce;

    public NonceService(int nonceByteAmount = 32)
    {
        var nonceBytes = new byte[nonceByteAmount];
        _rng.GetBytes(nonceBytes);
        _nonce = Convert.ToBase64String(nonceBytes);
    }

    public string GetNonce()
    {
        return _nonce;
    }
}

OWIN 中间件和扩展

public class SecurityHeaderMiddleware : OwinMiddleware
{
    private readonly INonceService _nonceService = null;
    public SecurityHeaderMiddleware(OwinMiddleware next, INonceService nonceService) : base(next)
    {
        _nonceService = nonceService;
    }

    public override async Task Invoke(IOwinContext context)
    {
        await Next.Invoke(context);

        var nonce = _nonceService.GetNonce();
        var csp = BuildCSPHeader(nonce);
        context.Response.Headers.Add(key, csp);
    }
}

public static class OwinExtensions
{
    private const string SecurityHeaderRegistrationKey = "SecurityHeaders";

    public static IAppBuilder UseSecurityHeader(this IAppBuilder app, INonceService nonceService)
    {
        if (app == null)
            throw new ArgumentNullException("app");

        if (app.Properties.ContainsKey(SecurityHeaderRegistrationKey))
            return app;

        app.Use<SecurityHeaderMiddleware>(nonceService);
        app.Properties.Add(SecurityHeaderRegistrationKey, true);
        return app;
    }
}

我使用 Unity 作为容器,所以我使用 PerRequestLifetimeManager 注册 INonceService

container.RegisterType<INonceService, NonceService>(new PerRequestLifetimeManager(), new InjectionConstructor(32));

我在 startup.cs 中向 OWIN 注册了我的自定义中间件

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    { 
        var nonceService = ServiceLocator.Current.GetInstance<INonceService>();
        app.UseSecurityHeader(nonceService);
    }
}

注意 如果无法按请求创建 OWIN 中间件,那么至少我应该如何将每个请求的新 NonceService 实例传递给中间件。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-5 owin unity-container owin-middleware


    【解决方案1】:

    查看我收到的HttpContext 的空引用异常时的堆栈跟踪,似乎中间件是在BuildWebHost 中从Main 构造的。

    我也在使用 Unity,所以我将构造函数依赖项从...更改为...

    IUserRepository userRepository

    Func&lt;IUserRepository&gt; userRepositoryFactory

    我的方法调用来自...

    userRepository.FetchLoggedInUser(userIdentifier);
    

    userRepositoryFactory().FetchLoggedInUser(userIdentifier);
    

    方便,Unity 自动生成工厂,因此无需编辑注册。

    【讨论】:

      最近更新 更多