Soubory cookie HTTP ve webovém rozhraní API ASP.NET

Toto téma popisuje, jak odesílat a přijímat soubory cookie HTTP ve webovém rozhraní API.

Úvod do souborů cookie HTTP

Tato část obsahuje stručný přehled toho, jak se soubory cookie implementují na úrovni HTTP. Podrobnosti najdete v dokumentu RFC 6265.

Soubor cookie je část dat, která server odesílá v odpovědi HTTP. Klient (volitelně) uloží soubor cookie a vrátí ho na následné žádosti. To umožňuje klientovi a serveru sdílet stav. Pokud chcete nastavit soubor cookie, server do odpovědi zahrne hlavičku Set-Cookie. Formát souboru cookie je pár název-hodnota s volitelnými atributy. Například:

Set-Cookie: session-id=1234567

Tady je příklad s atributy:

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

Pokud chcete na server vrátit soubor cookie, klient do pozdějších požadavků zahrne hlavičku cookie.

Cookie: session-id=1234567

Diagram procesu vrácení souboru cookie na server, během kterého klient obsahuje hlavičku cookie v pozdějších požadavcích

Odpověď HTTP může obsahovat více hlaviček Set-Cookie.

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

Klient vrátí více souborů cookie pomocí jedné hlavičky cookie.

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

Rozsah a doba trvání souboru cookie se řídí následujícími atributy v hlavičce Set-Cookie:

  • Doména: Řekne klientovi, která doména by měla soubor cookie přijímat. Pokud je například doména "example.com", klient vrátí soubor cookie do každé subdomény example.com. Pokud není zadaný, doména je serverem původu.
  • Cesta: Omezí soubor cookie na zadanou cestu v rámci domény. Pokud není určeno, použije se cesta identifikátoru URI požadavku.
  • Platnost vyprší: Nastaví datum vypršení platnosti souboru cookie. Klient odstraní soubor cookie, jakmile vyprší jeho platnost.
  • Max-Age: Nastaví maximální věk souboru cookie. Klient odstraní soubor cookie, když dosáhne maximálního věku.

Pokud jsou obě Expires i Max-Age nastavené, Max-Age má přednost. Pokud není nastaveno ani jedno, klient po skončení aktuální relace cookie odstraní. (Přesný význam relace je určen uživatelským agentem.)

Mějte však na paměti, že klienti mohou soubory cookie ignorovat. Uživatel může například zakázat soubory cookie z důvodů ochrany osobních údajů. Klienti mohou soubory cookie odstranit před vypršením jejich platnosti nebo omezit počet uložených souborů cookie. Z důvodů ochrany osobních údajů klienti často odmítnou soubory cookie třetích stran, kde doména neodpovídá zdrojovému serveru. Stručně řečeno, server by neměl spoléhat na vrácení souborů cookie, které nastavuje.

Soubory cookie ve webovém rozhraní API

Chcete-li přidat soubor cookie do odpovědi HTTP, vytvořte instanci CookieHeaderValue , která představuje soubor cookie. Pak zavolejte AddCookies rozšiřující metodu, která je definována v System.Net.Http. HttpResponseHeadersExtensions – třída pro přidání souboru cookie.

Například následující kód přidá soubor cookie v rámci akce kontroleru:

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;
}

Všimněte si, že AddCookies přebírá pole instancí CookieHeaderValue.

Chcete-li extrahovat soubory cookie z požadavku klienta, zavolejte metodu GetCookies :

string sessionId = "";

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

CookieHeaderValue obsahuje kolekci instancí CookieState. Každý cookieState představuje jeden soubor cookie. Jak je znázorněno, použijte metodu indexátoru k získání CookieState podle názvu.

Mnoho prohlížečů omezuje počet souborů cookie, které budou ukládat – celkový počet i počet na doménu. Proto může být užitečné umístit strukturovaná data do jednoho souboru cookie místo nastavení více souborů cookie.

Poznámka:

RFC 6265 nedefinuje strukturu dat souborů cookie.

Pomocí CookieHeaderValue třídy můžete předat seznam párů name-value pro data cookie. Tyto páry název-hodnota jsou kódovány jako data formuláře kódovaná adresou URL v hlavičce 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 });

Předchozí kód vytvoří následující hlavičku Set-Cookie:

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

Třída CookieState poskytuje metodu indexeru pro čtení dílčích hodnot ze souboru cookie ve zprávě požadavku:

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"];
}

Příklad: Nastavení a načtení souborů cookie v obslužné rutině zprávy

Předchozí příklady ukázaly, jak používat soubory cookie z kontroleru webového rozhraní API. Další možností je použít obslužné rutiny zpráv. Obslužné rutiny zpráv se volají dříve v procesu než kontrolery. Obslužná rutina zprávy může číst soubory cookie z požadavku předtím, než požadavek dosáhne kontroleru, nebo přidat soubory cookie do odpovědi poté, co kontroler vygeneruje odpověď.

Diagram procesu pro nastavení a příjem souborů cookie v obslužné rutině zprávy Ukazuje, jak se obslužné rutiny zpráv vyvolávají dříve v kanálu než kontrolery.

Následující kód ukazuje zpracování zpráv pro generování session ID. ID relace je uloženo v souboru cookie. Obslužná rutina zkontroluje požadavek na soubor cookie relace. Pokud požadavek neobsahuje soubor cookie, obslužná rutina vygeneruje nové ID relace. V obou případech obslužná rutina ukládá ID relace do balíčku vlastnosti HttpRequestMessage.Properties . Přidá také soubor cookie relace do odpovědi HTTP.

Tato implementace neověřuje, zda ID relace od klienta bylo skutečně vydáno serverem. Nepoužívejte ho jako formu ověřování! Příkladem je zobrazení správy souborů cookie 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 může získat ID relace z balíčku vlastností HttpRequestMessage.Properties .

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

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