다음을 통해 공유


ASP.NET Web API의 HTTP 쿠키

이 항목에서는 Web API에서 HTTP 쿠키를 보내고 받는 방법을 설명합니다.

HTTP 쿠키에 대한 배경

이 섹션에서는 HTTP 수준에서 쿠키를 구현하는 방법에 대한 간략한 개요를 제공합니다. 자세한 내용은 RFC 6265를 참조하세요.

쿠키는 서버가 HTTP 응답에서 보내는 데이터 조각입니다. 클라이언트(선택 사항)는 쿠키를 저장하고 후속 요청에 대해 반환합니다. 이렇게 하면 클라이언트와 서버가 상태를 공유할 수 있습니다. 쿠키를 설정하기 위해 서버에는 응답에 Set-Cookie 헤더가 포함됩니다. 쿠키의 형식은 선택적 특성이 있는 이름-값 쌍입니다. 예:

Set-Cookie: session-id=1234567

특성이 있는 예제는 다음과 같습니다.

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

서버에 쿠키를 반환하기 위해 클라이언트는 이후 요청에 쿠키 헤더를 포함합니다.

Cookie: session-id=1234567

클라이언트가 이후 요청에 쿠키 헤더를 포함하는 동안 서버에 쿠키를 반환하는 프로세스의 다이어그램.

HTTP 응답에는 여러 Set-Cookie 헤더가 포함될 수 있습니다.

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

클라이언트는 단일 쿠키 헤더를 사용하여 여러 쿠키를 반환합니다.

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

쿠키의 scope 및 기간은 Set-Cookie 헤더의 다음 특성에 의해 제어됩니다.

  • 도메인: 쿠키를 받아야 하는 도메인을 클라이언트에 알려줍니다. 예를 들어 도메인이 "example.com"인 경우 클라이언트는 example.com 모든 하위 도메인에 쿠키를 반환합니다. 지정하지 않으면 도메인이 원본 서버입니다.
  • 경로: 쿠키를 도메인 내의 지정된 경로로 제한합니다. 지정하지 않으면 요청 URI의 경로가 사용됩니다.
  • 만료: 쿠키의 만료 날짜를 설정합니다. 클라이언트는 쿠키가 만료되면 쿠키를 삭제합니다.
  • Max-Age: 쿠키의 최대 기간을 설정합니다. 클라이언트는 최대 연령에 도달하면 쿠키를 삭제합니다.

및 가 모두 Expires 설정된 경우 가 Max-Age 우선 Max-Age 합니다. 둘 다 설정되지 않으면 클라이언트는 현재 세션이 종료되면 쿠키를 삭제합니다. ("세션"의 정확한 의미는 사용자 에이전트에 의해 결정됩니다.)

그러나 클라이언트는 쿠키를 무시할 수 있습니다. 예를 들어 사용자는 개인 정보 보호를 위해 쿠키를 사용하지 않도록 설정할 수 있습니다. 클라이언트는 만료되기 전에 쿠키를 삭제하거나 저장된 쿠키 수를 제한할 수 있습니다. 개인 정보 보호를 위해 클라이언트는 도메인이 원본 서버와 일치하지 않는 "타사" 쿠키를 거부하는 경우가 많습니다. 즉, 서버는 설정한 쿠키를 다시 가져오는 데 의존해서는 안 됩니다.

Web API의 쿠키

HTTP 응답에 쿠키를 추가하려면 쿠키를 나타내는 CookieHeaderValue instance 만듭니다. 그런 다음 System.Net.Http에 정의된 AddCookies 확장 메서드를 호출 합니다. 쿠키를 추가하려면 HttpResponseHeadersExtensions 클래스입니다.

예를 들어 다음 코드는 컨트롤러 작업 내에 쿠키를 추가합니다.

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

AddCookiesCookieHeaderValue 인스턴스의 배열을 사용합니다.

클라이언트 요청에서 쿠키를 추출하려면 GetCookies 메서드를 호출합니다.

string sessionId = "";

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

CookieHeaderValue에는 CookieState 인스턴스의 컬렉션이 포함되어 있습니다. 각 CookieState 는 하나의 쿠키를 나타냅니다. 표시된 것처럼 인덱서 메서드를 사용하여 이름별로 CookieState 를 가져옵니다.

많은 브라우저에서 저장할 쿠키 수(총 수 및 도메인당 수)를 제한합니다. 따라서 여러 쿠키를 설정하는 대신 구조적 데이터를 단일 쿠키에 배치하는 것이 유용할 수 있습니다.

참고

RFC 6265는 쿠키 데이터의 구조를 정의하지 않습니다.

CookieHeaderValue 클래스를 사용하여 쿠키 데이터에 대한 이름-값 쌍 목록을 전달할 수 있습니다. 이러한 이름-값 쌍은 Set-Cookie 헤더에서 URL로 인코딩된 양식 데이터로 인코딩됩니다.

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

이전 코드는 다음 Set-Cookie 헤더를 생성합니다.

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

CookieState 클래스는 요청 메시지의 쿠키에서 하위 값을 읽을 수 있는 인덱서 메서드를 제공합니다.

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

예: 메시지 처리기에서 쿠키 설정 및 검색

이전 예제에서는 Web API 컨트롤러 내에서 쿠키를 사용하는 방법을 보여 줍니다. 또 다른 옵션은 메시지 처리기를 사용하는 것입니다. 메시지 처리기는 컨트롤러보다 먼저 파이프라인에서 호출됩니다. 메시지 처리기는 요청이 컨트롤러에 도달하기 전에 요청에서 쿠키를 읽거나 컨트롤러가 응답을 생성한 후 응답에 쿠키를 추가할 수 있습니다.

메시지 처리기에서 쿠키를 설정하고 수신하는 프로세스의 다이어그램 메시지 처리기가 컨트롤러보다 먼저 파이프라인에서 호출되는 방법을 보여 줍니다.

다음 코드에서는 세션 ID를 만들기 위한 메시지 처리기를 보여 줍니다. 세션 ID는 쿠키에 저장됩니다. 처리기는 세션 쿠키에 대한 요청을 확인합니다. 요청에 쿠키가 포함되지 않은 경우 처리기는 새 세션 ID를 생성합니다. 두 경우 모두 처리기는 HttpRequestMessage.Properties 속성 모음에 세션 ID를 저장합니다. 또한 HTTP 응답에 세션 쿠키를 추가합니다.

이 구현은 클라이언트의 세션 ID가 실제로 서버에서 발급되었는지 확인하지 않습니다. 인증의 한 형태로 사용하지 마세요! 예제의 요점은 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;
    }
}

컨트롤러는 HttpRequestMessage.Properties 속성 모음에서 세션 ID를 가져올 수 있습니다.

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

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