ASP.NET_SessionId + OWIN Cookies werden nicht an den Browser gesendet


145

Ich habe ein seltsames Problem mit der Verwendung der Owin-Cookie-Authentifizierung.

Wenn ich meine IIS-Serverauthentifizierung starte, funktioniert sie unter IE / Firefox und Chrome einwandfrei.

Ich habe angefangen, einige Tests mit Authentifizierung durchzuführen und mich auf verschiedenen Plattformen anzumelden, und bin auf einen seltsamen Fehler gestoßen. Sporadisch sendet das Owin Framework / IIS einfach keine Cookies an die Browser. Ich werde einen Benutzernamen und ein Passwort eingeben, die korrekt sind. Der Code wird ausgeführt, aber es wird überhaupt kein Cookie an den Browser gesendet. Wenn ich den Server neu starte, funktioniert er. Irgendwann werde ich versuchen, mich anzumelden, und erneut werden keine Cookies mehr geliefert. Das Überschreiten des Codes bewirkt nichts und wirft keine Fehler auf.

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

Und innerhalb meines Anmeldevorgangs habe ich den folgenden Code:

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

Update 1: Es scheint, dass eine Ursache des Problems darin besteht, dass beim Hinzufügen von Elementen zur Sitzung die Probleme beginnen. Das Hinzufügen von etwas Einfachem wie Session.Content["ABC"]= 123scheint das Problem zu schaffen.

Was ich erkennen kann, ist Folgendes: 1) (Chrome) Wenn ich mich anmelde, erhalte ich ASP.NET_SessionId + mein Authentifizierungscookie. 2) Ich gehe zu einer Seite, auf der eine Sitzung festgelegt wird. Inhalt ... 3) Öffnen Sie einen neuen Browser (Firefox) und versuchen Sie sich anzumelden. Es wird weder eine ASP.NET_SessionId empfangen noch ein Authentifizierungs-Cookie hat die ASP.NET_SessionId, die weiterhin funktioniert. Sobald ich dieses Cookie entferne, hat es das gleiche Problem wie alle anderen Browser, an denen ich an der IP-Adresse (10.xxx) und dem lokalen Host arbeite.

Update 2:ASPNET_SessionId Erzwinge die Erstellung von zuerst auf meiner login_load-Seite vor der Authentifizierung mit OWIN.

1) Bevor ich mich bei OWIN authentifiziere, mache ich Session.Contentauf meiner Anmeldeseite einen zufälligen Wert, um die ASP.NET_SessionId zu starten. 2) Dann authentifiziere ich mich und führe weitere Sitzungen durch. 3) Andere Browser scheinen jetzt zu funktionieren

Das ist bizarr. Ich kann nur schlussfolgern, dass dies etwas mit ASP und OWIN zu tun hat, die glauben, dass sie sich in verschiedenen Bereichen befinden oder so ähnlich.

Update 3 - Seltsames Verhalten zwischen den beiden.

Zusätzliches seltsames Verhalten festgestellt - Timeout der Owin- und ASP-Sitzung ist unterschiedlich. Was ich sehe, ist, dass meine Owin-Sitzungen durch einen Mechanismus länger am Leben bleiben als meine ASP-Sitzungen. Also beim Anmelden: 1.) Ich habe eine Cookie-basierte Authentifizierungssitzung 2.) Ich habe einige Sitzungsvariablen festgelegt

Meine Sitzungsvariablen (2) "sterben", bevor die Sitzungsvariable owin cookie eine erneute Anmeldung erzwingt, was zu unerwartetem Verhalten in meiner gesamten Anwendung führt. (Person ist angemeldet, aber nicht wirklich angemeldet)

Update 3B

Nach einigem Graben sah ich einige Kommentare auf einer Seite, die besagten, dass das Zeitlimit für die "Formular" -Authentifizierung und das Sitzungszeitlimit übereinstimmen müssen. Ich denke normalerweise, dass die beiden synchron sind, aber aus irgendeinem Grund sind die beiden nicht synchron.

Zusammenfassung der Problemumgehungen

1) Erstellen Sie vor der Authentifizierung immer zuerst eine Sitzung. Erstellen Sie grundsätzlich eine Sitzung, wenn Sie die Anwendung startenSession["Workaround"] = 0;

2) [Experimentell] Wenn Sie Cookies beibehalten, stellen Sie sicher, dass Ihr OWIN-Zeitlimit / Ihre Länge länger ist als Ihr sessionTimeout in Ihrer web.config (beim Testen).


1
Kann bestätigen, dass das Hinzufügen eines Sitzungsaufrufs zu ActionResult Login und ActionResult ExternalLogin dieses Problem behoben hat. Ich bin sicher, dass nur einer benötigt wird, aber ich habe beide an Ort und Stelle.
Scott

Vielen Dank! ... Das Hinzufügen einer Sitzung in ExternalLogin hat das Problem für mich behoben ... das ist Voodoo-Magie ... Ich habe bereits 6 Stunden damit verschwendet, dieses Problem zu
beheben

Antworten:


159

Ich bin auf dasselbe Problem gestoßen und habe die Ursache auf die Implementierung des OWIN ASP.NET-Hostings zurückgeführt. Ich würde sagen, es ist ein Fehler.

Einige Hintergrundinformationen

Meine Ergebnisse basieren auf diesen Baugruppenversionen:

  • Microsoft.Owin, Version = 2.0.2.0, Kultur = neutral, PublicKeyToken = 31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb, Version = 2.0.2.0, Kultur = neutral, PublicKeyToken = 31bf3856ad364e35
  • System.Web, Version = 4.0.0.0, Kultur = neutral, PublicKeyToken = b03f5f7f11d50a3a

OWIN verwendet eine eigene Abstraktion, um mit Antwort-Cookies ( Microsoft.Owin.ResponseCookieCollection ) zu arbeiten. Diese Implementierung umschließt die Sammlung der Antwortheader direkt und aktualisiert den Set-Cookie- Header entsprechend. Der OWIN ASP.NET-Host ( Microsoft.Owin.Host.SystemWeb ) umschließt nur System.Web.HttpResponse und seine Headersammlung. Wenn also über OWIN ein neues Cookie erstellt wird, wird der Set-Cookie- Header der Antwort direkt geändert.

ASP.NET verwendet jedoch auch eine eigene Abstraktion, um mit Antwort-Cookies zu arbeiten. Dies wird uns als System.Web.HttpResponse.Cookies- Eigenschaft zur Verfügung gestellt und von der versiegelten Klasse System.Web.HttpCookieCollection implementiert . Diese Implementierung umschließt den Set-Cookie- Header der Antwort nicht direkt, sondern verwendet einige Optimierungen und eine Handvoll interner Benachrichtigungen, um den geänderten Status des Antwortobjekts zu manifestieren.

Dann gibt es einen Punkt spät in der Anforderungslebensdauer, an dem der geänderte Status von HttpCookieCollection getestet wird ( System.Web.HttpResponse.GenerateResponseHeadersForCookies () ) und Cookies in den Set-Cookie- Header serialisiert werden . Wenn sich diese Sammlung in einem bestimmten Zustand befindet, wird der gesamte Set-Cookie-Header zuerst gelöscht und aus den in der Sammlung gespeicherten Cookies neu erstellt.

Die Implementierung der ASP.NET-Sitzung verwendet die System.Web.HttpResponse.Cookies- Eigenschaft, um das Cookie ASP.NET_SessionId zu speichern. Außerdem gibt es einige grundlegende Optimierungen im ASP.NET-Sitzungsstatusmodul ( System.Web.SessionState.SessionStateModule ), die über die statische Eigenschaft s_sessionEverSet implementiert wurden und selbsterklärend sind. Wenn Sie jemals etwas für den Sitzungsstatus in Ihrer Anwendung speichern, erledigt dieses Modul für jede Anforderung etwas mehr Arbeit.


Zurück zu unserem Login-Problem

Mit all diesen Stücken können Ihre Szenarien erklärt werden.

Fall 1 - Sitzung wurde nie festgelegt

System.Web.SessionState.SessionStateModule , s_sessionEverSet-Eigenschaft ist false. Vom Sitzungsstatusmodul werden keine Sitzungs-IDs generiert, und der System.Web.HttpResponse.Cookies- Erfassungsstatus wird nicht als geändert erkannt . In diesem Fall werden OWIN-Cookies korrekt an den Browser gesendet und die Anmeldung funktioniert.

Fall 2 - Die Sitzung wurde irgendwo in der Anwendung verwendet, jedoch nicht, bevor der Benutzer versucht, sich zu authentifizieren

System.Web.SessionState.SessionStateModule , s_sessionEverSet-Eigenschaft ist true. Sitzungs- IDs werden von SessionStateModule generiert . ASP.NET_SessionId wird zur System.Web.HttpResponse.Cookies- Auflistung hinzugefügt, aber später in der Anforderungslebensdauer entfernt, da die Sitzung des Benutzers tatsächlich leer ist. In diesem Fall wird der Erfassungsstatus von System.Web.HttpResponse.Cookies als geändert erkannt und der Set-Cookie- Header wird zuerst gelöscht, bevor Cookies auf den Header-Wert serialisiert werden.

In diesem Fall gehen OWIN-Antwortcookies "verloren" und der Benutzer wird nicht authentifiziert und zur Anmeldeseite zurückgeleitet.

Fall 3 - Sitzung wird verwendet, bevor der Benutzer versucht, sich zu authentifizieren

System.Web.SessionState.SessionStateModule , s_sessionEverSet-Eigenschaft ist true. Sitzungs- IDs werden von SessionStateModule generiert . ASP.NET_SessionId wird zu System.Web.HttpResponse.Cookies hinzugefügt . Aufgrund der internen Optimierung in System.Web.HttpCookieCollection und System.Web.HttpResponse.GenerateResponseHeadersForCookies () wird der Set-Cookie-Header NICHT zuerst gelöscht, sondern nur aktualisiert.

In diesem Fall werden sowohl OWIN-Authentifizierungscookies als auch ASP.NET_SessionId-Cookies als Antwort gesendet und die Anmeldung funktioniert.


Allgemeineres Problem mit Cookies

Wie Sie sehen, ist das Problem allgemeiner und nicht auf die ASP.NET-Sitzung beschränkt. Wenn Sie OWIN über Microsoft.Owin.Host.SystemWeb hosten und Sie / etwas die System.Web.HttpResponse.Cookies- Sammlung direkt verwenden , sind Sie gefährdet.

Zum Beispiel funktioniert dies und beide Cookies werden korrekt an den Browser gesendet ...

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

    return View();
}

Aber dies bedeutet nicht und OwinCookie „verloren“ ...

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

    return View();
}

Beide wurden von VS2013, IISExpress und der Standard-MVC-Projektvorlage getestet.


7
Ich habe einige Tage damit verbracht, dieses Problem in unserer Testumgebung zu debuggen und zu beheben. Die einzige Problemumgehung, die ich gefunden habe, ist die gleiche, die Sie vorgeschlagen haben (Sitzung einstellen, bevor sich der Benutzer authentifiziert). Ich habe das Problem an katanaproject gemeldet ... katanaproject.codeplex.com/workitem/197 , also wird dort vielleicht jemand einen Kommentar abgeben .
Tomas Dolezal

11
Dies ist ein ziemlich schwerwiegender Fehler, zumal sie in der Vorlage für vs2013 verpackt sind.
Piotr Stulinski

2
Für alle, die dies weiter untersuchen
möchten

1
Dieses Problem tritt aufgrund der Verwendung von Controller.TempData auf, das Session als Sicherungsspeicher verwendet. Kann die Unfähigkeit, sich anzumelden, leicht reproduzieren, wenn aus einer vorherigen Anforderung kein ASP_NET.SessionId-Cookie vorhanden ist.
Kingdango

2
Schließlich! Was für ein seltsames Problem das ist. Danke dir. Dies ist immer noch ein Problem über zwei Jahre, nachdem diese Antwort geschrieben wurde.
Spivonious

43

Beginnend mit der großartigen Analyse von @TomasDolezal habe ich mir sowohl die Owin- als auch die System.Web-Quelle angesehen.

Das Problem ist, dass System.Web über eine eigene Hauptquelle für Cookie-Informationen verfügt und dies nicht der Set-Cookie-Header ist. Owin kennt nur den Set-Cookie-Header. Eine Problemumgehung besteht darin, sicherzustellen, dass alle von Owin gesetzten Cookies auch in der HttpContext.Current.Response.CookiesSammlung gesetzt werden.

Ich habe eine kleine Middleware ( Quelle , Nuget ) erstellt, die genau das tut und die unmittelbar über der Registrierung der Cookie-Middleware platziert werden soll.

app.UseKentorOwinCookieSaver();

app.UseCookieAuthentication(new CookieAuthenticationOptions());

1
Ich werde es versuchen. Seit ich nach asp.net Identity 2.2.0-alpha1 Probleme hatte, nicht nur beim Anmelden, sondern auch beim Abmelden des Benutzers (der Benutzer wird sich beim Abmelden nicht abmelden, klicken Sie im Allgemeinen auf |, falls ich die Website für einige Zeit offen gelassen habe ohne etwas zu tun |) .. Und nach dem Einstellen einer Sitzung kurz bevor sich der Benutzer anmeldet, wurde das Anmeldeproblem behoben, aber das Abmeldeproblem bleibt bestehen. Vielen Dank für Ihre Mühe. Übrigens, gibt es etwas, das ich tun sollte, außer die Installation von das Paket?
Werben

Sie müssen es mit app.UseKentorCookieMiddlewareSaver();in Startup.Auth.cs aktivieren . Es sollte auch das Löschen von Abmeldecookies übernehmen.
Anders Abel

Vielen Dank Anders Abel, sowohl das Anmelden als auch das Abmelden funktionieren jetzt einwandfrei. Aber der Code im obigen Kommentar muss geändert werden (weil ich ihm gefolgt bin :) ohne Erfolg), um: app.UseKentorOwinCookieSaver()und möglicherweise in Ihrer ursprünglichen Antwort wie auf der GitHub-Seite des Pakets enthalten zu sein .
umwerben

1
Vielen Dank, dass Sie das falsche Dokument bemerkt haben. Es ist tatsächlich bereits auf der GitHub-Seite behoben, aber ich habe meine Antwort jetzt auch hier aktualisiert.
Anders Abel

@AndersAbel Ich versuche, Meetup-Anmeldungen für dieses Github-Projekt hinzuzufügen: github.com/owin-middleware/OwinOAuthProviders ''. Ich habe Asana erst neulich hinzugefügt und hatte keine Probleme, aber aus irgendeinem Grund gibt bei Meetup die warte AuthenticationManager.GetExternalLoginInfoAsync () -Methode in Account // ExternalLoginCallback null zurück. Leider hat Ihr NuGet-Paket mein Problem nicht gelöst. Ich habe mich gefragt, ob Sie etwas Zeit hatten, um mit mir zu sprechen, da Sie möglicherweise das Problem besser beheben und auf Ihr Projekt zugreifen können.
Anthony Ruffino

42

Kurz gesagt, der .NET-Cookie-Manager gewinnt den OWIN-Cookie-Manager und überschreibt die auf der OWIN-Ebene festgelegten Cookies . Das Update besteht darin, die SystemWebCookieManager-Klasse zu verwenden, die hier als Lösung für das Katana-Projekt bereitgestellt wird . Sie müssen diese oder eine ähnliche Klasse verwenden, wodurch OWIN gezwungen wird, den .NET-Cookie-Manager zu verwenden, damit keine Inkonsistenzen auftreten :

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

Weisen Sie es beim Start Ihrer Anwendung einfach zu, wenn Sie Ihre OWIN-Abhängigkeiten erstellen:

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

Eine ähnliche Antwort wurde hier gegeben, enthält jedoch nicht die gesamte Codebasis, die zur Lösung des Problems erforderlich ist. Ich sehe daher die Notwendigkeit, sie hier hinzuzufügen, da der externe Link zum Katana-Projekt möglicherweise ausfällt und dies vollständig aufgezeichnet werden sollte auch hier als Lösung.


danke, es funktioniert mir, aber ich lösche auch alle Sitzungen, indem ich diesen ControllerContext.HttpContext.Session.RemoveAll () aufrufe; in externallogincallback Funktion
Adnan

Gilt das für ASP.NET Webforms 4.6.1 ? Meine WebApp verwendetASP.NET Webforms, OWIN, ADFS
Kiquenet

@Kiquenet Verwendet Ihre Web-App OWIN-Cookies? Dann ja.
Alexandru

Im Code haben Startup.ConfigureAuthwir app.UseCookieAuthenticationund app.UseWsFederationAuthenticationund schließlich app.UseStageMarker
Kiquenet

@Alexandru Sie könnten eine Bearbeitung in Betracht ziehen, mein Team hat diesen Fehler entdeckt und es war selten und zufällig, es hat sich durch DEV- und UAT-Umgebungen vor uns versteckt. Dieses Zitat aus Ihrer Antwort galt nicht für uns: ".NET Cookie Manager wird immer gewinnen." Das wäre leicht zu finden und zu beheben, wenn die OWIN-Cookies immer überschrieben würden, hätte es keine unserer OIDC-Middleware von unseren Entwicklungsarbeitsplätzen geschafft. Aber die Zufälligkeit bedeutete, dass der Fehler 2 Tage lang bis zur Produktion reichte, bevor er uns in großem Maßstab traf (die Hälfte unserer internen Verwendungen konnte sich nicht über AAD anmelden). Stört es Sie, wenn ich das Wort "immer" aus Ihrer Antwort entferne?
Yzorg

17

Das Katana-Team antwortete auf das von Tomas Dolezar angesprochene Problem und veröffentlichte Dokumentationen zu Problemumgehungen :

Problemumgehungen lassen sich in zwei Kategorien einteilen. Eine Möglichkeit besteht darin, System.Web neu zu konfigurieren, damit die Response.Cookies-Sammlung nicht verwendet und die OWIN-Cookies nicht überschrieben werden. Der andere Ansatz besteht darin, die betroffenen OWIN-Komponenten neu zu konfigurieren, damit sie Cookies direkt in die Response.Cookies-Sammlung von System.Web schreiben.

  • Stellen Sie sicher, dass die Sitzung vor der Authentifizierung eingerichtet wurde: Der Konflikt zwischen System.Web- und Katana-Cookies tritt pro Anforderung auf, sodass die Anwendung die Sitzung möglicherweise auf eine bestimmte Anforderung vor dem Authentifizierungsablauf einrichten kann. Dies sollte einfach zu tun sein, wenn der Benutzer zum ersten Mal ankommt. Es kann jedoch schwieriger sein, später zu garantieren, wenn die Sitzungs- oder Authentifizierungscookies ablaufen und / oder aktualisiert werden müssen.
  • SessionStateModule deaktivieren - Wenn die Anwendung nicht auf Sitzungsinformationen angewiesen ist, das Sitzungsmodul jedoch weiterhin ein Cookie setzt, das den oben genannten Konflikt verursacht, können Sie das Sitzungsstatusmodul deaktivieren.
  • Konfigurieren Sie die CookieAuthenticationMiddleware so, dass sie direkt in die Cookie-Sammlung von System.Web schreibt.
app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

Siehe SystemWebCookieManager-Implementierung in der Dokumentation (Link oben)

Weitere Informationen hier

Bearbeiten

Nachfolgend finden Sie die Schritte, die wir zur Lösung des Problems unternommen haben. Sowohl 1. als auch 2. haben das Problem auch separat gelöst, aber wir haben beschlossen, beide nur für den Fall anzuwenden:

1. Verwenden Sie SystemWebCookieManager

2. Legen Sie die Sitzungsvariable fest:

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

(Randnotiz: Die obige Initialize-Methode ist der logische Ort für den Fix, da base.Initialize Session verfügbar macht. Der Fix kann jedoch auch später angewendet werden, da in OpenId zuerst eine anonyme Anforderung vorliegt, dann zum OpenId-Anbieter umgeleitet und dann zurück Die Probleme treten nach der Rückleitung zur App auf, während der Fix die Sitzungsvariable bereits während der ersten anonymen Anforderung festlegt, wodurch das Problem behoben wird, bevor überhaupt eine Rückleitung erfolgt.

Bearbeiten 2

Kopieren und Einfügen aus dem Katana-Projekt 14.05.2016:

Füge das hinzu:

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

...und das:

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

Ich finde diese Antwort viel einfacher und einfacher, das Problem zu beheben. Danke, - Vielleicht habe ich zu plötzlich gesprochen. Dies hat mein Problem nicht gelöst.
JCS

@JCS Enthält die Schritte, die wir zur Lösung des Problems unternommen haben. Haben Sie herausgefunden, ob Ihr Problem damit zusammenhängt?
Thomasius

Ich verwende Web Api 2 + Owin Middleware + Redis Cache für die Sitzungsverwaltung zur Authentifizierung. Ich habe versucht, SystemWebCookieManager zu verwenden, und das Problem, bei dem die Authentifizierungscookies nicht gesetzt wurden, wurde dadurch nicht gelöst. Die Verwendung von "UseKentorOwinCookieSaver" hat das Problem gelöst, aber ich mag keine zusätzliche externe Abhängigkeit ...
JCS

Das Löschen der Sitzung hat bei mir funktioniert. Keine externe Abhängigkeit erforderlich. Setzen Sie dies ControllerContext.HttpContext.Session.RemoveAll();in Ihre ExternalLogin()Aktion ein, bevor Sie anrufen ChallengeResult(). Ich weiß nicht, ob es die beste Lösung ist, aber es ist die einfachste.
Alisson

1
@chemitaxis sicher, beachten Sie einfach, dass der ?.(null-bedingte Operator) nur in C # 6 funktioniert.
Alisson

5

Es wurden bereits Antworten bereitgestellt, aber in Version 3.1.0 gibt es eine SystemWebChunkingCookieManager-Klasse, die verwendet werden kann.

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

Ist das in 3.1.0 immer noch ein Problem?
Cyberconte

1
Ja, es ist immer noch ein Problem in 3.1.0 für mich und ich brauchte diesen Cookie-Manager, da der Standard immer noch der ChunkingCookieManager ist.
Jonmeyer

kann wo verwendet werden? und wie?
Simon_Weaver

@ Jonmeyer danke. Ich denke, gestern habe ich die Unterscheidung zwischen SystemCCM und CCM verpasst, also werde ich das auf jeden Fall überprüfen
Simon_Weaver

Selbst nach dem Hinzufügen der obigen Zeile funktioniert es bei mir nicht. Ich benutze die Version 3.1.0. Hauptsächlich kann ich mich zum ersten Mal anmelden, aber nach dem Abmelden kann ich mich nicht anmelden.
Mitin Dixit

3

Wenn Sie selbst Cookies in der OWIN-Middleware setzen, OnSendingHeadersscheint die Verwendung das Problem zu umgehen.

Beispielsweise wird die Verwendung des folgenden Codes owinResponseCookie2festgelegt, obwohl dies owinResponseCookie1nicht der Fall ist:

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

3

Ich hatte ein ähnliches Problem mit Visual Studio 2017 und .net MVC 5.2.4 . Das Aktualisieren von Nuget Microsoft.Owin.Security.Google auf die neueste Version, die derzeit 4.0.1 ist, hat für mich funktioniert! Hoffe das hilft jemandem!


1
Habe meinen Speck auf diesem gerettet! Hatte ein Problem mit Android Chrome, bei dem die Authentifizierung zufällig verloren ging. Nichts anderes in diesem Thread hat funktioniert. Ich benutze VS2019 und ASP MVC 5.
zfrank

2

Die schnellste einzeilige Codelösung:

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

Fügen Sie einfach diese Zeile vor der CreateIdentity-Methode hinzu:

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

1
Wo hast du diesen Code hingelegt HttpContext.Current.Session["RunSession"] = "1";? in Globa.asax Session_Start ?
Kiquenet

1
Es ist in der Tat die einfachste und schnellste verfügbare Lösung, und bis die Lösung dieses Problems nicht im Framework enthalten ist (dies wurde bereits angekündigt), würde ich zum Beispiel einen Einzeiler anstelle einer Klasse + einer Reihe von Abhängigkeiten bevorzugen . Diese Lösung wird meiner Meinung nach unterschätzt.
Der Zinger

Ich habe es in meinem AuthManager oben in der IssueAuthToken-Methode hinzugefügt
Alexander Trofimov

1

Ich hatte das gleiche Symptom, dass der Set-Cookie-Header nicht gesendet wurde, aber keine dieser Antworten half mir. Alles funktionierte auf meinem lokalen Computer, aber wenn es für die Produktion bereitgestellt wurde, wurden die Set-Cookie-Header niemals gesetzt.

Es stellte sich heraus, dass es sich um eine Kombination aus der Verwendung eines benutzerdefinierten CookieAuthenticationMiddlewareProgramms mit WebApi und der Unterstützung der WebApi-Komprimierung handelte

Zum Glück habe ich ELMAH in meinem Projekt verwendet, wodurch ich diese Ausnahme protokollieren konnte:

System.Web.HttpException Server kann keinen Header anhängen, nachdem HTTP-Header gesendet wurden.

Was mich zu diesem GitHub-Problem führte

Wenn Sie ein seltsames Setup wie das meine haben, sollten Sie die Komprimierung für Ihre WebApi-Controller / -Methoden, die Cookies setzen, deaktivieren oder das ausprobieren OwinServerCompressionHandler.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.