Pliki cookie protokołu HTTP we wzorcu ASP.NET Web API

W tym temacie opisano sposób wysyłania i odbierania plików cookie HTTP w internetowym interfejsie API.

Tło na plikach cookie HTTP

Ta sekcja zawiera krótkie omówienie sposobu implementowania plików cookie na poziomie protokołu HTTP. Aby uzyskać szczegółowe informacje, zapoznaj się z dokumentem RFC 6265.

Plik cookie to element danych wysyłanych przez serwer w odpowiedzi HTTP. Klient (opcjonalnie) przechowuje plik cookie i zwraca go w kolejnych żądaniach. Dzięki temu klient i serwer mogą udostępniać stan. Aby ustawić plik cookie, serwer zawiera nagłówek Set-Cookie w odpowiedzi. Format pliku cookie jest parą nazwa-wartość z atrybutami opcjonalnymi. Na przykład:

Set-Cookie: session-id=1234567

Oto przykład z atrybutami:

Set-Cookie: session-id=1234567; max-age=86400; domain=example.com; path=/;

Aby zwrócić plik cookie na serwer, klient dołącza nagłówek cookie w kolejnych żądaniach.

Cookie: session-id=1234567

Diagram przedstawiający proces zwracania pliku cookie na serwer, podczas którego klient dołącza nagłówek cookie w kolejnych żądaniach.

Odpowiedź HTTP może zawierać wiele nagłówków Set-Cookie.

Set-Cookie: session-token=abcdef;
Set-Cookie: session-id=1234567;

Klient zwraca wiele plików cookie przy użyciu jednego nagłówka pliku cookie.

Cookie: session-id=1234567; session-token=abcdef;

Zakres i czas trwania pliku cookie są kontrolowane przez następujące atrybuty w nagłówku Set-Cookie:

  • Domena: informuje klienta, który domena powinna odbierać plik cookie. Jeśli na przykład domena ma wartość "example.com", klient zwraca plik cookie do każdej poddomeny example.com. Jeśli nie zostanie określony, domena jest serwerem pochodzenia.
  • Ścieżka: ogranicza plik cookie do określonej ścieżki w domenie. Jeśli nie zostanie określony, zostanie użyta ścieżka identyfikatora URI żądania.
  • Wygasa: ustawia datę wygaśnięcia pliku cookie. Klient usuwa plik cookie po wygaśnięciu.
  • Max-Age: określa maksymalny wiek pliku cookie. Klient usuwa plik cookie, gdy osiągnie maksymalny wiek.

Jeśli obie Expires wartości i Max-Age są ustawione, Max-Age pierwszeństwo ma. Jeśli żadna z nich nie zostanie ustawiona, klient usunie plik cookie po zakończeniu bieżącej sesji. (Dokładne znaczenie "sesji" zależy od agenta użytkownika).

Należy jednak pamiętać, że klienci mogą ignorować pliki cookie. Na przykład użytkownik może wyłączyć pliki cookie ze względów prywatności. Klienci mogą usuwać pliki cookie przed wygaśnięciem lub ograniczyć liczbę przechowywanych plików cookie. Ze względu na prywatność klienci często odrzucają pliki cookie "innych firm", w których domena nie jest zgodna z serwerem pochodzenia. Krótko mówiąc, serwer nie powinien polegać na przywracaniu plików cookie, które ustawia.

Pliki cookie w internetowym interfejsie API

Aby dodać plik cookie do odpowiedzi HTTP, utwórz wystąpienie CookieHeaderValue reprezentujące plik cookie. Następnie wywołaj metodę rozszerzenia AddCookies , która jest zdefiniowana w pliku System.Net.Http. HttpResponseHeadersExtensions , klasa , aby dodać plik cookie.

Na przykład poniższy kod dodaje plik cookie w ramach akcji kontrolera:

public HttpResponseMessage Get()
{
    var resp = new HttpResponseMessage();

    var cookie = new CookieHeaderValue("session-id", "12345");
    cookie.Expires = DateTimeOffset.Now.AddDays(1);
    cookie.Domain = Request.RequestUri.Host;
    cookie.Path = "/";

    resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });
    return resp;
}

Zwróć uwagę, że funkcja AddCookies przyjmuje tablicę wystąpień CookieHeaderValue .

Aby wyodrębnić pliki cookie z żądania klienta, wywołaj metodę GetCookies :

string sessionId = "";

CookieHeaderValue cookie = Request.Headers.GetCookies("session-id").FirstOrDefault();
if (cookie != null)
{
    sessionId = cookie["session-id"].Value;
}

Wartość CookieHeaderValue zawiera kolekcję wystąpień CookieState . Każdy element CookieState reprezentuje jeden plik cookie. Użyj metody indeksatora, aby uzyskać wartość CookieState według nazwy, jak pokazano poniżej.

Wiele przeglądarek ogranicza liczbę plików cookie, które będą przechowywane — zarówno łączną liczbę, jak i liczbę na domenę. W związku z tym może być przydatne umieszczenie danych strukturalnych w jednym pliku cookie zamiast ustawiania wielu plików cookie.

Uwaga

RFC 6265 nie definiuje struktury danych plików cookie.

Korzystając z klasy CookieHeaderValue , można przekazać listę par name-value dla danych plików cookie. Te pary nazwa-wartość są kodowane jako dane formularza zakodowane w adresie URL w nagłówku Set-Cookie:

var resp = new HttpResponseMessage();

var nv = new NameValueCollection();
nv["sid"] = "12345";
nv["token"] = "abcdef";
nv["theme"] = "dark blue";
var cookie = new CookieHeaderValue("session", nv); 

resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });

Poprzedni kod tworzy następujący nagłówek Set-Cookie:

Set-Cookie: session=sid=12345&token=abcdef&theme=dark+blue;

Klasa CookieState udostępnia metodę indeksatora do odczytywania podwartych wartości z pliku cookie w komunikacie żądania:

string sessionId = "";
string sessionToken = "";
string theme = "";

CookieHeaderValue cookie = Request.Headers.GetCookies("session").FirstOrDefault();
if (cookie != null)
{
    CookieState cookieState = cookie["session"];

    sessionId = cookieState["sid"];
    sessionToken = cookieState["token"];
    theme = cookieState["theme"];
}

Przykład: ustawianie i pobieranie plików cookie w programie obsługi komunikatów

W poprzednich przykładach pokazano, jak używać plików cookie z poziomu kontrolera internetowego interfejsu API. Inną opcją jest użycie programów obsługi komunikatów. Programy obsługi komunikatów są wywoływane wcześniej w potoku niż kontrolery. Program obsługi komunikatów może odczytywać pliki cookie z żądania przed dotarciem do kontrolera lub dodać pliki cookie do odpowiedzi po wygenerowaniu odpowiedzi przez kontroler.

Diagram procesu ustawiania i odbierania plików cookie w programie obsługi komunikatów. Ilustruje, jak programy obsługi komunikatów są wywoływane wcześniej w potoku niż kontrolery.

Poniższy kod przedstawia procedurę obsługi komunikatów na potrzeby tworzenia identyfikatorów sesji. Identyfikator sesji jest przechowywany w pliku cookie. Procedura obsługi sprawdza żądanie pliku cookie sesji. Jeśli żądanie nie zawiera pliku cookie, program obsługi generuje nowy identyfikator sesji. W obu przypadkach program obsługi przechowuje identyfikator sesji w torbie właściwości HttpRequestMessage.Properties . Dodaje również plik cookie sesji do odpowiedzi HTTP.

Ta implementacja nie sprawdza, czy identyfikator sesji z klienta został rzeczywiście wystawiony przez serwer. Nie używaj go jako formy uwierzytelniania! Punktem przykładu jest pokazanie zarządzania plikami cookie PROTOKOŁU HTTP.

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;

public class SessionIdHandler : DelegatingHandler
{
    public static string SessionIdToken = "session-id";

    async protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string sessionId;

        // Try to get the session ID from the request; otherwise create a new ID.
        var cookie = request.Headers.GetCookies(SessionIdToken).FirstOrDefault();
        if (cookie == null)
        {
            sessionId = Guid.NewGuid().ToString();
        }
        else 
        {
            sessionId = cookie[SessionIdToken].Value;
            try
            {
                Guid guid = Guid.Parse(sessionId);
            }
            catch (FormatException)
            {
                // Bad session ID. Create a new one.
                sessionId = Guid.NewGuid().ToString();
            }
        }

        // Store the session ID in the request property bag.
        request.Properties[SessionIdToken] = sessionId;

        // Continue processing the HTTP request.
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        // Set the session ID as a cookie in the response message.
        response.Headers.AddCookies(new CookieHeaderValue[] {
            new CookieHeaderValue(SessionIdToken, sessionId) 
        });

        return response;
    }
}

Kontroler może uzyskać identyfikator sesji z torby właściwości HttpRequestMessage.Properties .

public HttpResponseMessage Get()
{
    string sessionId = Request.Properties[SessionIdHandler.SessionIdToken] as string;

    return new HttpResponseMessage()
    {
        Content = new StringContent("Your session ID = " + sessionId)
    };
}