ASP .NET Core webapi устанавливает cookie в промежуточном программном обеспечении - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь установить cookie после выполнения действия, изо всех сил пытаясь заставить это работать. Мне удалось увидеть cookie, если я установил его с контроллера, но не из промежуточного программного обеспечения. Я играл с порядком конфигурации и ничего. Пример кода взят из чистого проекта, созданного webapi, поэтому, если кто-то захочет поиграть с ним, просто, просто создайте пустой webapi, добавьте класс CookieSet и замените класс Startup на приведенный ниже (добавлены только параметры политики cookie)

Вот мое промежуточное ПО

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 это останавливает выполнение, поэтому происходит что-то, что я не могу понять.

А вот и мой класс Startup

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 и ничего.

1 Ответ

1 голос
/ 07 июня 2019

Хорошо, я говорю с собой, но это для сообщества ...

Получил это после копания в коде AspNetCore. По сути, файл cookie должен быть установлен для обратного вызова OnStarting контекстного ответа. Вот код промежуточного программного обеспечения, которое делает трюк

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 использует для этого внутренний класс.

Проверка класса SessionMiddleware, часть кода выглядит следующим образом (много чего удалено только ради ответа):

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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...