Cookies HTTP no ASP.NET Web APIHTTP Cookies in ASP.NET Web API

por Mike Wassonby Mike Wasson

Este tópico descreve como enviar e receber cookies HTTP na API da Web.This topic describes how to send and receive HTTP cookies in Web API.

Plano de fundo em cookies HTTPBackground on HTTP Cookies

Esta seção fornece uma breve visão geral de como os cookies são implementados no nível de HTTP.This section gives a brief overview of how cookies are implemented at the HTTP level. Para obter detalhes, consulte RFC 6265.For details, consult RFC 6265.

Um cookie é um dado que um servidor envia na resposta HTTP.A cookie is a piece of data that a server sends in the HTTP response. O cliente (opcionalmente) armazena o cookie e o retorna em solicitações subsequentes.The client (optionally) stores the cookie and returns it on subsequent requests. Isso permite que o cliente e o servidor compartilhem o estado.This allows the client and server to share state. Para definir um cookie, o servidor inclui um cabeçalho Set-cookie na resposta.To set a cookie, the server includes a Set-Cookie header in the response. O formato de um cookie é um par de nome-valor, com atributos opcionais.The format of a cookie is a name-value pair, with optional attributes. Por exemplo:For example:

Set-Cookie: session-id=1234567

Aqui está um exemplo com atributos:Here is an example with attributes:

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

Para retornar um cookie ao servidor, o cliente inclui um cabeçalho de cookie em solicitações posteriores.To return a cookie to the server, the client includes a Cookie header in later requests.

Cookie: session-id=1234567

Uma resposta HTTP pode incluir vários cabeçalhos Set-cookie.An HTTP response can include multiple Set-Cookie headers.

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

O cliente retorna vários cookies usando um único cabeçalho de cookie.The client returns multiple cookies using a single Cookie header.

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

O escopo e a duração de um cookie são controlados pelos seguintes atributos no cabeçalho Set-Cookie:The scope and duration of a cookie are controlled by following attributes in the Set-Cookie header:

  • Domínio: informa ao cliente qual domínio deve receber o cookie.Domain: Tells the client which domain should receive the cookie. Por exemplo, se o domínio for "example.com", o cliente retornará o cookie para cada subdomínio de example.com.For example, if the domain is "example.com", the client returns the cookie to every subdomain of example.com. Se não for especificado, o domínio será o servidor de origem.If not specified, the domain is the origin server.
  • Caminho: restringe o cookie para o caminho especificado dentro do domínio.Path: Restricts the cookie to the specified path within the domain. Se não for especificado, o caminho do URI de solicitação será usado.If not specified, the path of the request URI is used.
  • Expiraem: define uma data de validade para o cookie.Expires: Sets an expiration date for the cookie. O cliente exclui o cookie quando ele expira.The client deletes the cookie when it expires.
  • Max-age: define a idade máxima para o cookie.Max-Age: Sets the maximum age for the cookie. O cliente exclui o cookie quando atinge a idade máxima.The client deletes the cookie when it reaches the maximum age.

Se Expires e Max-Age forem definidos, Max-Age terá precedência.If both Expires and Max-Age are set, Max-Age takes precedence. Se nenhum for definido, o cliente excluirá o cookie quando a sessão atual terminar.If neither is set, the client deletes the cookie when the current session ends. (O significado exato de "sessão" é determinado pelo agente do usuário.)(The exact meaning of "session" is determined by the user-agent.)

No entanto, lembre-se de que os clientes podem ignorar cookies.However, be aware that clients may ignore cookies. Por exemplo, um usuário pode desabilitar cookies por motivos de privacidade.For example, a user might disable cookies for privacy reasons. Os clientes podem excluir cookies antes de expirarem ou limitar o número de cookies armazenados.Clients may delete cookies before they expire, or limit the number of cookies stored. Por motivos de privacidade, os clientes geralmente rejeitam cookies "terceiros", em que o domínio não corresponde ao servidor de origem.For privacy reasons, clients often reject "third party" cookies, where the domain does not match the origin server. Em suma, o servidor não deve confiar na obtenção dos cookies que ele define.In short, the server should not rely on getting back the cookies that it sets.

Cookies na API da WebCookies in Web API

Para adicionar um cookie a uma resposta HTTP, crie uma instância CookieHeaderValue que representa o cookie.To add a cookie to an HTTP response, create a CookieHeaderValue instance that represents the cookie. Em seguida, chame o método de extensão Addcookies , que é definido no sistema .net. http. Classe HttpResponseHeadersExtensions , para adicionar o cookie.Then call the AddCookies extension method, which is defined in the System.Net.Http. HttpResponseHeadersExtensions class, to add the cookie.

Por exemplo, o código a seguir adiciona um cookie dentro de uma ação do controlador:For example, the following code adds a cookie within a controller action:

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

Observe que Addcookies usa uma matriz de instâncias de CookieHeaderValue .Notice that AddCookies takes an array of CookieHeaderValue instances.

Para extrair os cookies de uma solicitação do cliente, chame o método getCookies :To extract the cookies from a client request, call the GetCookies method:

string sessionId = "";

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

Um CookieHeaderValue contém uma coleção de instâncias de cookiestate .A CookieHeaderValue contains a collection of CookieState instances. Cada cookiestate representa um cookie.Each CookieState represents one cookie. Use o método indexador para obter um cookiestate por nome, como mostrado.Use the indexer method to get a CookieState by name, as shown.

Muitos navegadores limitam quantos cookies armazenarão—o número total e o número por domínio.Many browsers limit how many cookies they will store—both the total number, and the number per domain. Portanto, pode ser útil colocar dados estruturados em um único cookie, em vez de definir vários cookies.Therefore, it can be useful to put structured data into a single cookie, instead of setting multiple cookies.

Note

A RFC 6265 não define a estrutura de dados do cookie.RFC 6265 does not define the structure of cookie data.

Usando a classe CookieHeaderValue , você pode passar uma lista de pares de nome-valor para os dados do cookie.Using the CookieHeaderValue class, you can pass a list of name-value pairs for the cookie data. Esses pares de nome-valor são codificados como dados de formulário codificados em URL no cabeçalho Set-Cookie:These name-value pairs are encoded as URL-encoded form data in the Set-Cookie header:

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

O código anterior produz o seguinte cabeçalho Set-Cookie:The previous code produces the following Set-Cookie header:

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

A classe cookiestate fornece um método de indexador para ler os subvalors de um cookie na mensagem de solicitação:The CookieState class provides an indexer method to read the sub-values from a cookie in the request message:

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

Exemplo: definir e recuperar cookies em um manipulador de mensagensExample: Set and Retrieve Cookies in a Message Handler

Os exemplos anteriores mostraram como usar cookies de dentro de um controlador de API da Web.The previous examples showed how to use cookies from within a Web API controller. Outra opção é usar manipuladores de mensagens.Another option is to use message handlers. Os manipuladores de mensagens são invocados anteriormente no pipeline do que os controladores.Message handlers are invoked earlier in the pipeline than controllers. Um manipulador de mensagens pode ler cookies da solicitação antes que a solicitação atinja o controlador ou adicionar cookies à resposta depois que o controlador gerar a resposta.A message handler can read cookies from the request before the request reaches the controller, or add cookies to the response after the controller generates the response.

O código a seguir mostra um manipulador de mensagens para a criação de IDs de sessão.The following code shows a message handler for creating session IDs. A ID da sessão é armazenada em um cookie.The session ID is stored in a cookie. O manipulador verifica a solicitação para o cookie de sessão.The handler checks the request for the session cookie. Se a solicitação não incluir o cookie, o manipulador gerará uma nova ID de sessão.If the request does not include the cookie, the handler generates a new session ID. Em ambos os casos, o manipulador armazena a ID de sessão no recipiente de propriedades HttpRequestMessage. Properties .In either case, the handler stores the session ID in the HttpRequestMessage.Properties property bag. Ele também adiciona o cookie de sessão à resposta HTTP.It also adds the session cookie to the HTTP response.

Essa implementação não valida se a ID da sessão do cliente foi realmente emitida pelo servidor.This implementation does not validate that the session ID from the client was actually issued by the server. Não o use como uma forma de autenticação!Don't use it as a form of authentication! O ponto do exemplo é mostrar o gerenciamento de cookies HTTP.The point of the example is to show HTTP cookie management.

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

Um controlador pode obter a ID de sessão do recipiente de propriedades HttpRequestMessage. Properties .A controller can get the session ID from the HttpRequestMessage.Properties property bag.

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

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