ASP .NET Core Webapi在中间件中设置cookie [英] ASP .NET Core webapi set cookie in middleware

查看:132
本文介绍了ASP .NET Core Webapi在中间件中设置cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在执行动作后设置一个cookie,努力使它正常工作.如果我是从控制器而不是从中间件设置的,我设法看到了它. 我玩过配置的顺序,一无所获. 该代码示例来自一个干净的webapi创建的项目,因此,如果有人想玩它很简单,只需创建一个空的webapi,添加CookieSet类,然后将Startup类替换为下面的类(仅添加cookie策略选项)

I'm trying to set a cookie after the action is executed, struggling to get this working. I managed to see the cookie if I set it from a controller, but not from a middleware. I have played with the order of the configuration and nothing. The code sample is from a clean webapi created project, so if someone wants to play with it is simple, just create an empty webapi, add the CookieSet class and replace the Startup class with the one below (only added are the cookie policy options)

这是我的中间件

public class CookieSet
{
    private readonly RequestDelegate _next;

    public CookieSet(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next.Invoke(context);
        var cookieOptions = new CookieOptions()
        {
            Path = "/",
            Expires = DateTimeOffset.UtcNow.AddHours(1),
            IsEssential = true,
            HttpOnly = false,
            Secure = false,
        };
        context.Response.Cookies.Append("test", "cookie", cookieOptions);
        var p = 1;
        p++;
    }
}

我已经添加了p赋值并检查了执行是否永不完成,在Cookies.Append行上它停止了执行,所以发生了某些事情,我无法弄清.

I have added the p assignment and checked that the execution never gets there, on the Cookies.Append line it stops the execution, so there is something going on I can't figure it out.

这是我的启动课程

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => false;
            options.MinimumSameSitePolicy = SameSiteMode.None;
            options.HttpOnly = HttpOnlyPolicy.None;
            options.Secure = CookieSecurePolicy.None;
            // you can add more options here and they will be applied to all cookies (middleware and manually created cookies)
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseCookiePolicy(new CookiePolicyOptions
        {
            CheckConsentNeeded = c => false,
            HttpOnly = HttpOnlyPolicy.None,
            Secure = CookieSecurePolicy.None,
            MinimumSameSitePolicy = SameSiteMode.None,
        });

        app.UseMiddleware<CookieSet>();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}

我将所有选项都设置为最低要求,并通过chrome和fiddler进行了测试,什么也没有.

I have set all the options to the minimum requirements, tested with chrome and fiddler and nothing.

推荐答案

好,我是在自言自语,但这是为了社区...

Ok, I'm talking to myself, but this is for the community...

在深入研究AspNetCore代码后,可以进行此工作. 基本上,必须在上下文响应的回调OnStarting上设置cookie. 这是实现窍门的中间件代码

Got this working after digging into the AspNetCore code. Basically the cookie must be set on the callback OnStarting of the context response. Here is the code of the middleware that makes the trick

public class CookieSet
{
    private readonly RequestDelegate _next;
    private readonly ASessionOptions _options;
    private HttpContext _context;
    public CookieSet(RequestDelegate next, IOptions<ASessionOptions> options)
    {
        _next = next;
        _options = options.Value;
    }

    public async Task Invoke(HttpContext context)
    {
        _context = context;
        context.Response.OnStarting(OnStartingCallBack);
        await _next.Invoke(context);
    }

    private Task OnStartingCallBack()
    {
        var cookieOptions = new CookieOptions()
        {
            Path = "/",
            Expires = DateTimeOffset.UtcNow.AddHours(1),
            IsEssential = true,
            HttpOnly = false,
            Secure = false,
        };
        _context.Response.Cookies.Append("MyCookie", "TheValue", cookieOptions);
        return Task.FromResult(0);
    }
}

AspNetCore团队为此使用了一个内部类.

The AspNetCore team uses an internal class for that.

检查SessionMiddleware类,部分代码如下(为了回答而删除了很多东西):

Checking the SessionMiddleware class, part of the code is as follows (removed a lot of things just for the sake of the answer):

public class SessionMiddleware
{
    public async Task Invoke(HttpContext context)
    {
        // Removed code here

        if (string.IsNullOrWhiteSpace(sessionKey) || sessionKey.Length != SessionKeyLength)
        {
                        // Removed code here
            var establisher = new SessionEstablisher(context, cookieValue, _options);
            tryEstablishSession = establisher.TryEstablishSession;
            isNewSessionKey = true;
        }

        // Removed code here

        try
        {
            await _next(context);
        }

        // Removed code here
    }

    //Now the inner class

    private class SessionEstablisher
    {
        private readonly HttpContext _context;
        private readonly string _cookieValue;
        private readonly SessionOptions _options;
        private bool _shouldEstablishSession;

        public SessionEstablisher(HttpContext context, string cookieValue, SessionOptions options)
        {
            _context = context;
            _cookieValue = cookieValue;
            _options = options;
            context.Response.OnStarting(OnStartingCallback, state: this);
        }

        private static Task OnStartingCallback(object state)
        {
            var establisher = (SessionEstablisher)state;
            if (establisher._shouldEstablishSession)
            {
                establisher.SetCookie();
            }
            return Task.FromResult(0);
        }

        private void SetCookie()
        {
            var cookieOptions = _options.Cookie.Build(_context);

            var response = _context.Response;
            response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions);

            var responseHeaders = response.Headers;
            responseHeaders[HeaderNames.CacheControl] = "no-cache";
            responseHeaders[HeaderNames.Pragma] = "no-cache";
            responseHeaders[HeaderNames.Expires] = "-1";
        }

        // Returns true if the session has already been established, or if it still can be because the response has not been sent.
        internal bool TryEstablishSession()
        {
            return (_shouldEstablishSession |= !_context.Response.HasStarted);
        }
    }
}

这篇关于ASP .NET Core Webapi在中间件中设置cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆