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

时间:2017-04-28 21:33:45

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

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

但是我的问题是我无法按要求注册自定义中间件。

当我调试时,我注意到OWIN NOT 为每个请求创建自定义中间件的新实例,并且因为所有请求都使用相同的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 Middleware&扩展

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作为conatiner,所以我使用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 个答案:

答案 0 :(得分:0)

查看我收到的HttpContext空引用异常时的堆栈跟踪,似乎中间件是在BuildWebHost的{​​{1}}中构建的。

我也在使用Unity,所以我改变了构造函数依赖...

Main

IUserRepository userRepository

我的方法来自......

Func<IUserRepository> userRepositoryFactory

userRepository.FetchLoggedInUser(userIdentifier);

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