HTTP-Cookies in der ASP.NET-Web-API
In diesem Thema wird das Senden und Empfangen von HTTP-Cookies in der Web-API beschrieben.
Hintergrund zu HTTP-Cookies
Dieser Abschnitt bietet einen kurzen Überblick darüber, wie Cookies auf HTTP-Ebene implementiert werden. Ausführliche Informationen finden Sie unter RFC 6265.
Ein Cookie ist ein Datenteil, das ein Server in der HTTP-Antwort sendet. Der Client speichert (optional) das Cookie und gibt es bei nachfolgenden Anforderungen zurück. Dadurch können Client und Server den Zustand gemeinsam nutzen. Um ein Cookie festzulegen, enthält der Server einen Set-Cookie-Header in der Antwort. Das Format eines Cookies ist ein Name-Wert-Paar mit optionalen Attributen. Zum Beispiel:
Set-Cookie: session-id=1234567
Hier sehen Sie ein Beispiel mit Attributen:
Set-Cookie: session-id=1234567; max-age=86400; domain=example.com; path=/;
Um ein Cookie an den Server zurückzugeben, enthält der Client in späteren Anforderungen einen Cookie-Header.
Cookie: session-id=1234567
Eine HTTP-Antwort kann mehrere Set-Cookie-Header enthalten.
Set-Cookie: session-token=abcdef;
Set-Cookie: session-id=1234567;
Der Client gibt mithilfe eines einzelnen Cookie-Headers mehrere Cookies zurück.
Cookie: session-id=1234567; session-token=abcdef;
Der Umfang und die Dauer eines Cookies werden durch die folgenden Attribute im Set-Cookie-Header gesteuert:
- Domäne: Teilt dem Client mit, welche Domäne das Cookie erhalten soll. Wenn die Domäne beispielsweise "example.com" ist, gibt der Client das Cookie an jede Unterdomäne von example.com zurück. Wenn nicht angegeben, ist die Domäne der Ursprungsserver.
- Pfad: Schränkt das Cookie auf den angegebenen Pfad innerhalb der Domäne ein. Falls nicht angegeben, wird der Pfad des Anforderungs-URI verwendet.
- Läuft ab: Legt ein Ablaufdatum für das Cookie fest. Der Client löscht das Cookie, wenn es abläuft.
- Max-Age: Legt das maximale Alter für das Cookie fest. Der Client löscht das Cookie, wenn es das maximale Alter erreicht.
Wenn beide Expires
und Max-Age
festgelegt sind, Max-Age
hat Vorrang. Wenn keines festgelegt ist, löscht der Client das Cookie, wenn die aktuelle Sitzung endet. (Die genaue Bedeutung von "Sitzung" wird vom User-Agent bestimmt.)
Beachten Sie jedoch, dass Clients Cookies möglicherweise ignorieren. Beispielsweise kann ein Benutzer Cookies aus Datenschutzgründen deaktivieren. Kunden können Cookies löschen, bevor sie ablaufen, oder die Anzahl der gespeicherten Cookies einschränken. Aus Datenschutzgründen lehnen Clients häufig Cookies von Drittanbietern ab, bei denen die Domäne nicht mit dem Ursprungsserver übereinstimmt. Kurz gesagt, der Server sollte sich nicht darauf verlassen, die gesetzten Cookies zurück zu erhalten.
Cookies in der Web-API
Um einer HTTP-Antwort ein Cookie hinzuzufügen, erstellen Sie eine CookieHeaderValue-instance, die das Cookie darstellt. Rufen Sie dann die AddCookies-Erweiterungsmethode auf, die in System.Net.Http definiert ist. HttpResponseHeadersExtensions-Klasse , um das Cookie hinzuzufügen.
Der folgende Code fügt beispielsweise ein Cookie innerhalb einer Controlleraktion hinzu:
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;
}
Beachten Sie, dass AddCookies ein Array von CookieHeaderValue-Instanzen verwendet.
Um die Cookies aus einer Clientanforderung zu extrahieren, rufen Sie die GetCookies-Methode auf :
string sessionId = "";
CookieHeaderValue cookie = Request.Headers.GetCookies("session-id").FirstOrDefault();
if (cookie != null)
{
sessionId = cookie["session-id"].Value;
}
Ein CookieHeaderValue enthält eine Auflistung von CookieState-Instanzen . Jeder CookieState stellt ein Cookie dar. Verwenden Sie die Indexer-Methode, um einen CookieState nach Namen abzurufen, wie gezeigt.
Strukturierte Cookiedaten
Viele Browser beschränken die Anzahl von Cookies, die sie speichern – sowohl die Gesamtzahl als auch die Anzahl pro Domäne. Daher kann es sinnvoll sein, strukturierte Daten in einem einzelnen Cookie zu platzieren, anstatt mehrere Cookies zu setzen.
Hinweis
RFC 6265 definiert nicht die Struktur von Cookiedaten.
Mit der CookieHeaderValue-Klasse können Sie eine Liste von Name-Wert-Paaren für die Cookiedaten übergeben. Diese Name-Wert-Paare werden als URL-codierte Formulardaten im Set-Cookie-Header codiert:
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 });
Der vorherige Code erzeugt den folgenden Set-Cookie-Header:
Set-Cookie: session=sid=12345&token=abcdef&theme=dark+blue;
Die CookieState-Klasse stellt eine Indexermethode zum Lesen der Unterwerte aus einem Cookie in der Anforderungsnachricht bereit:
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"];
}
Beispiel: Festlegen und Abrufen von Cookies in einem Nachrichtenhandler
In den vorherigen Beispielen wurde gezeigt, wie Sie Cookies innerhalb eines Web-API-Controllers verwenden. Eine weitere Option besteht darin, Nachrichtenhandler zu verwenden. Nachrichtenhandler werden früher in der Pipeline aufgerufen als Controller. Ein Nachrichtenhandler kann Cookies aus der Anforderung lesen, bevor die Anforderung den Controller erreicht, oder der Antwort Cookies hinzufügen, nachdem der Controller die Antwort generiert hat.
Der folgende Code zeigt einen Nachrichtenhandler zum Erstellen von Sitzungs-IDs. Die Sitzungs-ID wird in einem Cookie gespeichert. Der Handler überprüft die Anforderung für das Sitzungscooky. Wenn die Anforderung das Cookie nicht enthält, generiert der Handler eine neue Sitzungs-ID. In beiden Fällen speichert der Handler die Sitzungs-ID im Eigenschaftenbehälter HttpRequestMessage.Properties . Außerdem wird das Sitzungscooky der HTTP-Antwort hinzugefügt.
Diese Implementierung überprüft nicht, ob die Sitzungs-ID vom Client tatsächlich vom Server ausgestellt wurde. Verwenden Sie es nicht als Authentifizierung! Der Punkt des Beispiels besteht darin, die HTTP-Cookieverwaltung anzuzeigen.
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;
}
}
Ein Controller kann die Sitzungs-ID aus dem Eigenschaftenbehälter httpRequestMessage.Properties abrufen.
public HttpResponseMessage Get()
{
string sessionId = Request.Properties[SessionIdHandler.SessionIdToken] as string;
return new HttpResponseMessage()
{
Content = new StringContent("Your session ID = " + sessionId)
};
}