如何根据请求创建 OWIN 中间件

Posted

技术标签:

【中文标题】如何根据请求创建 OWIN 中间件【英文标题】:How to create OWIN middleware per request 【发布时间】:2017-09-27 02:28:53 【问题描述】:

我正在实现一个自定义 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 实例传递给中间件。

【问题讨论】:

【参考方案1】:

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

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

IUserRepository userRepository

Func&lt;IUserRepository&gt; userRepositoryFactory

我的方法调用来自...

userRepository.FetchLoggedInUser(userIdentifier);

userRepositoryFactory().FetchLoggedInUser(userIdentifier);

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

【讨论】:

以上是关于如何根据请求创建 OWIN 中间件的主要内容,如果未能解决你的问题,请参考以下文章

Owin中间件动手玩

在我自己的 OWIN 中间件中使用 Ninject DI

修改 OWIN OAuth 中间件以使用 JWT 不记名令牌

Owin,在Authentication Request中传递自定义查询参数

如何将 Azure OpenIdConnect OWIN 中间件 Cookie Auth 转换为 SPA 应用程序的 JavaScript JWT?

OWIN 中间件可以使用 http 会话吗?