source

ASP.NET_SessionId + OWIN 쿠키가 브라우저로 전송되지 않음

ittop 2023. 5. 12. 22:39
반응형

ASP.NET_SessionId + OWIN 쿠키가 브라우저로 전송되지 않음

오윈 쿠키 인증을 사용하는 데 이상한 문제가 있습니다.

IIS 서버 인증을 시작하면 IE/Firefox 및 Chrome에서 완벽하게 작동합니다.

인증을 사용하여 테스트를 시작하고 다른 플랫폼에서 로그인을 시작했는데 이상한 오류가 발생했습니다.때때로 Owin 프레임워크 / IIS는 브라우저에 쿠키를 보내지 않습니다.코드가 실행되지만 쿠키가 브라우저에 전혀 전달되지 않는 올바른 사용자 이름과 암호를 입력합니다.서버를 다시 시작하면 서버가 작동하기 시작하고 로그인을 시도한 후 쿠키 배달을 중지합니다.코드를 건너면 아무 일도 하지 않고 오류도 발생하지 않습니다.

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true,
            AuthenticationType = "ABC",
            LoginPath = new PathString("/Account/Login"),
            CookiePath = "/",
            CookieName = "ABC",
            Provider = new CookieAuthenticationProvider
               {
                  OnApplyRedirect = ctx =>
                  {
                     if (!IsAjaxRequest(ctx.Request))
                     {
                        ctx.Response.Redirect(ctx.RedirectUri);
                     }
                 }
               }
        });

로그인 절차 내에 다음 코드가 있습니다.

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                            authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
    authentication.AuthenticationResponseGrant =
        new AuthenticationResponseGrant(identity, new AuthenticationProperties()
                                                   {
                                                       IsPersistent = isPersistent
                                                   });

authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);

업데이트 1: 세션에 항목을 추가하면 문제가 시작되는 것이 문제의 한 원인인 것 같습니다.다음과 같은 간단한 것 추가Session.Content["ABC"]= 123문제를 일으키는 것 같습니다.

제가 알 수 있는 것은 다음과 같습니다: 1) (크롬)로그인하면 ASP가 나옵니다.NET_SessionId + 내 인증 쿠키.session.contents를 설정하는 페이지로 이동합니다.새 브라우저(Firefox)를 열고 로그인을 시도해도 ASP가 수신되지 않습니다.NET_SessionId도 인증 쿠키를 얻지 못합니다. 4) 첫 번째 브라우저에는 ASP가 있습니다.NET_SessionId 계속 작동합니다.이 쿠키를 제거하는 순간 IP 주소(10.x.x.x) 및 localhost에서 작업 중인 다른 모든 브라우저와 동일한 문제가 발생합니다.

업데이트 2: 강제 생성ASPNET_SessionId 전에 표시됩니다. OWIN은 login_load를 사용합니다.

OWIN을 .Session.ContentASP를 시작하는 데 필요한 값입니다.후 3) 는 이제 작동하는처럼 보입니다. 3) NET_SessionId 2) 를 참조하십시오.

이건 이상해요.저는 이것이 ASP와 OWIN이 서로 다른 영역에 있다고 생각하는 것과 관련이 있다고 결론을 내릴 수 있을 뿐입니다.

업데이트 3 - 둘 사이의 이상한 행동

추가 이상 행동이 식별됨 - Owin 및 ASP 세션의 시간 초과가 다름제가 보고 있는 것은 제 Owin 세션이 어떤 메커니즘을 통해 ASP 세션보다 더 오래 지속되고 있다는 것입니다.그래서 로그인할 때: 1.)저는 쿠키 기반의 인증 세션 2가 있습니다.)몇 가지 세션 변수를 설정했습니다.

Owin cookie 세션 변수가 재로그인을 강제하기 전에 내 세션 변수(2) "die"가 발생하여 전체 응용 프로그램에서 예기치 않은 동작이 발생합니다. (사용자가 로그인되었지만 실제로 로그인하지는 않았습니다.)

업데이트 3B

좀 더 자세히 조사한 결과, 페이지에서 "양식" 인증 시간 제한과 세션 시간 제한이 일치해야 한다는 몇 가지 의견을 발견했습니다.저는 보통 두 가지가 잘 맞는다고 생각하지만, 어떤 이유에서인지 둘은 잘 맞지 않습니다.

해결 방법 요약

인증 전에 항상 세션을 먼저 작성합니다.할 때 을 만듭니다. 응 용 기 으 로 세 션 만 들 기 적Session["Workaround"] = 0;

[실험] 쿠키를 지속하는 경우 OWIN 제한 시간/시간이 세션보다 길어야 합니다.web.config의 시간 초과(테스트 중)

저는 동일한 문제에 직면하여 OWIN ASP로 원인을 추적했습니다.NET 호스팅 구현.저는 그것이 벌레라고 말할 수 있습니다.

약간의 배경

결과는 다음 어셈블리 버전을 기반으로 합니다.

  • 마이크로소프트.Owin, Version=2.0.2.0, Culture=중립, 공개 키토큰=31bf3856ad364e35
  • 마이크로소프트.오윈. 진행자.시스템 웹, 버전=2.0.2.0, Culture=중립, 공개 키토큰=31bf3856ad364e35
  • System.Web, Version=4.0.0.0, Culture=neutral, PublicKey토큰=b03f5f7f11d50a3a

OWIN은 자체 추상화를 사용하여 응답 쿠키(Microsoft)와 함께 작업합니다.Owin.ResponseCookieCollection).이 구현은 응답 헤더 컬렉션을 직접 래핑하여 Set-Cookie 헤더를 업데이트합니다.OWIN ASP.NET 호스트(Microsoft).오윈. 진행자.시스템 웹)은 시스템을 감쌀 뿐입니다.Web.HttpResponse 및 헤더 컬렉션입니다.따라서 OWIN을 통해 새 쿠키가 생성되면 응답 세트-쿠키 헤더가 직접 변경됩니다.

하지만 ASP.또한 NET은 자체 추상화를 사용하여 응답 쿠키를 사용합니다.이것은 우리에게 시스템으로 노출됩니다.Web.HttpResponse.쿠키 속성이며 봉인된 클래스 시스템에 의해 구현됩니다.Web.HttpCookieCollection.이 구현은 응답 세트-쿠키 헤더를 직접 래핑하지 않고 일부 최적화 및 소수의 내부 알림을 사용하여 응답 개체로 변경된 상태를 표시합니다.

그런 다음 HttpCookieCollection 변경 상태를 테스트하는 요청 수명이 늦은 시점이 있습니다(System).Web.HttpResponse.쿠키 및 쿠키에 대한 응답 헤더 생성() 및 쿠키는 설정-쿠키 헤더로 직렬화됩니다.이 컬렉션이 특정 상태일 경우 컬렉션에 저장된 쿠키에서 먼저 전체 Set-Cookie 헤더가 지워지고 다시 생성됩니다.

ASP.NET 세션 구현에서는 시스템을 사용합니다.Web.HttpResponse.ASP를 저장할 쿠키 속성입니다.NET_SessionId 쿠키입니다.또한 ASP에는 몇 가지 기본적인 최적화가 있습니다.NET 세션 상태 모듈(시스템).웹.세션 상태.SessionStateModule)은 s_sessionEverSet라는 정적 속성을 통해 구현되었으며 이는 매우 자명합니다.응용 프로그램에 세션 상태에 대한 내용을 저장하는 경우 이 모듈은 각 요청에 대해 약간 더 많은 작업을 수행합니다.


로그인 문제로 돌아가기

이 모든 조각으로 당신의 시나리오를 설명할 수 있습니다.

사례 1 - 세션이 설정되지 않았습니다.

시스템. 웹.세션 상태.SessionStateModule, s_sessionEverSet 속성이 false입니다.세션 상태 모듈 시스템에서 세션 ID가 생성되지 않았습니다.Web.HttpResponse.쿠키 수집 상태가 변경된 것으로 검색되지 않습니다.이 경우 OWIN 쿠키가 브라우저로 올바르게 전송되고 로그인이 작동합니다.

사례 2 - 세션이 응용 프로그램의 어딘가에서 사용되었지만 사용자가 인증을 시도하기 전에는 사용되지 않았습니다.

시스템. 웹.세션 상태.SessionStateModule, s_sessionEverSet 속성이 true입니다.세션 ID는 SessionStateModule, ASP에 의해 생성됩니다.NET_SessionId가 시스템에 추가되었습니다.Web.HttpResponse.쿠키 수집이지만 실제로 사용자 세션이 비어 있기 때문에 나중에 요청 기간에 제거됩니다.경우 시스템.Web.HttpResponse.쿠키 수집 상태가 변경된 것으로 탐지되고 쿠키가 헤더 값으로 직렬화되기 전에 Set-Cookie 헤더가 먼저 지워집니다.

이 경우 OWIN 응답 쿠키는 "손실"되고 사용자는 인증되지 않으며 로그인 페이지로 다시 리디렉션됩니다.

사례 3 - 사용자가 인증을 시도하기 전에 세션이 사용됩니다.

시스템. 웹.세션 상태.SessionStateModule, s_sessionEverSet 속성이 true입니다.세션 ID는 SessionStateModule, ASP에 의해 생성됩니다.NET_SessionId가 시스템에 추가되었습니다.Web.HttpResponse.쿠키.시스템의 내부 최적화로 인해.Web.HttpCookie 수집 및 시스템Web.HttpResponse.쿠키에 대한 응답 헤더 생성() 세트-쿠키 헤더는 처음에 삭제되지 않고 업데이트만 됩니다.

이 경우 OWIN 인증 쿠키와 ASP가 모두 사용됩니다.NET_SessionId 쿠키는 응답 및 로그인 작업으로 전송됩니다.


쿠키와 관련된 더 일반적인 경우

보시다시피 문제는 ASP에 국한되지 않고 더 일반적입니다.NET 세션.Microsoft를 통해 OWIN을 호스팅하는 경우.오윈. 진행자.시스템 웹 및 사용자/물건이 시스템을 직접 사용하고 있습니다.Web.HttpResponse.위험에 처한 쿠키 모음입니다.

를 들어, 이것이 작동하고 두 쿠키가 모두 브라우저로 올바르게 전송됩니다.

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";

    return View();
}

하지만 이것은 그렇지 않고 오윈 쿠키는 "잃어버린"...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";
    HttpContext.Response.Cookies.Remove("ASPCookie");

    return View();
}

둘 다 VS2013, II Express 및 기본 MVC 프로젝트 템플릿에서 테스트되었습니다.

한마디로.NET 쿠키 관리자가 OWIN 쿠키 관리자를 이기고 OWIN 계층에 설정된 쿠키를 덮어씁니다.이 문제는 여기서 카타나 프로젝트에 대한 솔루션으로 제공되는 SystemWebCookieManager 클래스를 사용하는 것입니다.이 클래스 또는 이 클래스와 유사한 클래스를 사용해야 합니다. 그러면 OWIN이 이 클래스를 사용하게 됩니다.불일치가 없도록 NET cookie manager:

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

응용 프로그램 시작 시 OWIN 종속성을 생성할 때 이를 할당하면 됩니다.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    ...
    CookieManager = new SystemWebCookieManager()
    ...
});

비슷한 답변이 여기에 제공되었지만 문제를 해결하는 데 필요한 코드 기반이 모두 포함되어 있지 않기 때문에 카타나 프로젝트의 외부 링크가 다운될 수 있으므로 여기에 추가할 필요가 있다고 생각합니다.

@Tomas Dolezal의 훌륭한 분석을 시작으로 Owin과 System 모두를 살펴보았습니다.웹 소스.

문제는 그 시스템입니다.웹에는 쿠키 정보의 마스터 소스가 있으며 이는 Set-Cookie 헤더가 아닙니다.Owin은 Set-Cookie 헤더에 대해서만 알고 있습니다.해결 방법은 Owin에 의해 설정된 쿠키도HttpContext.Current.Response.Cookies수집.

쿠키 미들웨어 등록 바로 위에 배치할 수 있는 작은 미들웨어(소스, 너겟)를 만들었습니다.

app.UseKentorOwinCookieSaver();

app.UseCookieAuthentication(new CookieAuthenticationOptions());

Katana 팀은 Tomas Dolezar가 제기한 문제에 대해 답변하고 해결 방법에 대한 문서를 게시했습니다.

해결 방법은 두 가지 범주로 나뉩니다.하나는 시스템을 재구성하는 것입니다.웹을 사용하여 응답을 사용하지 않습니다.쿠키 수집 및 OWIN 쿠키 덮어쓰기.다른 방법은 영향을 받는 OWIN 구성 요소를 재구성하여 시스템에 쿠키를 직접 기록하도록 하는 것입니다.웹의 응답.쿠키 모음입니다.

  • 인증 전에 세션이 설정되었는지 확인합니다.시스템 간의 충돌.웹 및 카타나 쿠키는 요청별로 제공되므로, 응용프로그램이 인증 흐름 전에 일부 요청에 대해 세션을 설정할 수 있습니다.이 작업은 사용자가 처음 도착했을 때 수행하기 쉬워야 하지만 나중에 세션 또는 인증 쿠키가 만료되거나 새로 고쳐야 할 때 수행하기가 더 어려울 수 있습니다.
  • 세션 상태 모듈 사용 안 함 - 응용 프로그램이 세션 정보에 의존하지 않지만 세션 모듈이 위의 충돌을 일으키는 쿠키를 설정하는 경우 세션 상태 모듈을 사용 안 함으로 설정할 수 있습니다.
  • 시스템에 직접 기록하도록 쿠키 인증 미들웨어를 재구성합니다.웹의 쿠키 모음입니다.
app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

설명서(위 링크)에서 SystemWebCookieManager 구현을 참조하십시오.

자세한 내용은 여기를 참조하십시오.

편집

아래는 문제를 해결하기 위해 취한 단계입니다.1.과 2. 모두 문제를 별도로 해결했지만 다음과 같은 경우를 대비해 둘 다 적용하기로 했습니다.

시스템 웹 쿠키 관리자 사용

세션 변수를 설정합니다.

protected override void Initialize(RequestContext requestContext)
{
    base.Initialize(requestContext);

    // See http://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser/
    requestContext.HttpContext.Session["FixEternalRedirectLoop"] = 1;
}

(측면 참고: 위의 Initialize 방법은 base이기 때문에 수정에 대한 논리적인 위치입니다.초기화하면 세션을 사용할 수 있습니다.그러나 OpenId에서 먼저 익명 요청이 발생한 다음 OpenId 공급자로 리디렉션한 다음 앱으로 다시 이동하기 때문에 수정 사항은 나중에 적용될 수도 있습니다.수정 프로그램이 첫 번째 익명 요청 중에 세션 변수를 이미 설정하여 리디렉션이 발생하기도 전에 문제를 해결하는 동안 앱으로 리디렉션한 후 문제가 발생합니다.)

편집 2

카타나 프로젝트 2016-05-14에서 복사 붙여넣기:

추가할 항목:

app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

...그리고 이것은:

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

이미 답변이 제공되었지만 3.1.0 버전에서는 SystemWebChunkingCookieManager 클래스를 사용할 수 있습니다.

https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs

https://raw.githubusercontent.com/aspnet/AspNetKatana/c33569969e79afd9fb4ec2d6bdff877e376821b2/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    ...
    CookieManager = new SystemWebChunkingCookieManager()
    ...
});

OWIN 미들웨어에서 쿠키를 직접 설정하는 경우 다음을 사용합니다.OnSendingHeaders문제를 해결하는 것처럼 보입니다.

를 들어, 아래의 입니다.owinResponseCookie2설정될 것입니다, 그럼에도 불구하고.owinResponseCookie1다음이 아닙니다.

private void SetCookies()
{
    var owinContext = HttpContext.GetOwinContext();
    var owinResponse = owinContext.Response;

    owinResponse.Cookies.Append("owinResponseCookie1", "value1");

    owinResponse.OnSendingHeaders(state =>
    {
        owinResponse.Cookies.Append("owinResponseCookie2", "value2");
    },
    null);

    var httpResponse = HttpContext.Response;
    httpResponse.Cookies.Remove("httpResponseCookie1");
}

Visual Studio 2017 및 .net MVC 5.2.4의 Nuget Microsoft 업데이트와 관련된 유사한 문제에 직면했습니다.오윈. 보안.구글에서 현재 4.0.1 버전의 최신 버전까지 제게 도움이 되었습니다!이것이 누군가를 돕기를 바랍니다!

가장 빠른 한 줄 코드 솔루션:

HttpContext.Current.Session["RunSession"] = "1";

CreateIdentity 메서드 앞에 이 행을 추가하면 됩니다.

HttpContext.Current.Session["RunSession"] = "1";
var userIdentity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
_authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = rememberLogin }, userIdentity);

Set-Cookie 헤더가 전송되지 않는 동일한 증상이 있었지만 이러한 답변은 도움이 되지 않았습니다.모든 것이 로컬 컴퓨터에서 작동했지만 프로덕션에 배포되면 쿠키 헤더가 설정되지 않습니다.

그것은 관습을 사용하는 것의 조합이었던 것으로 밝혀졌습니다.CookieAuthenticationMiddlewareWebApi와 함께 WebApi 압축 지원

다행히도 저는 제 프로젝트에서 ELMAH를 사용하고 있었는데, 이 예외를 로그에 기록할 수 있었습니다.

시스템. 웹.HTTP 헤더를 보낸 후에는 HttpException Server에서 헤더를 추가할 수 없습니다.

그래서 이 깃허브 문제가 발생했습니다.

기본적으로, 만약 당신이 나처럼 이상한 설정을 가지고 있다면, 당신은 쿠키를 설정하는 당신의 WebApi 컨트롤러/메소드에 대한 압축을 비활성화하고 싶을 것입니다. 또는 시도해 보세요.OwinServerCompressionHandler.

언급URL : https://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser

반응형