158 votes

ASP.NET_SessionId + OWIN Les cookies ne sont pas envoyés au navigateur.

J'ai un problème étrange avec l'aide d'Owin cookie d'authentification.

Lorsque je démarre mon serveur IIS authentification fonctionne parfaitement bien sur IE/Firefox et Chrome.

J'ai commencé à faire quelques essais avec d'Authentification et de connexion sur différentes plates-formes et je suis venu avec une étrange erreur. Sporadiquement, Owin cadre / IIS juste ne pas envoyer des cookies dans les navigateurs. Je vous tapez un nom d'utilisateur et un mot de passe est correct, le code fonctionne, mais aucun témoin n'est livré dans le navigateur. Si je redémarre le serveur, il commence à travailler à un certain moment, je vais essayer de connexion et de nouveau les cookies cesser de se livrer. En passant sur le code ne fait rien et ne renvoie pas d'erreur.

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

Et dans ma procédure de connexion, j'ai le code suivant:

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)

;

Mise à jour 1: Il semble que l'une des causes du problème, c'est quand j'ai ajouter des éléments à la session de la que les problèmes commencent. L'ajout de quelque chose de simple comme la Session.Contenu["ABC"]= 123 semble créer le problème.

Ce que je peux faire est la suivante: 1) (Chrome)Quand je me connecte je obtenir de l'ASP.NET_SessionId + mon cookie d'authentification. 2) je vais à une page qui définit une session.table des matières... 3) Ouvrir une nouvelle fenêtre de navigateur (Firefox) et essayez de vous connecter et qu'il ne reçoit pas un ASP.NET_SessionId ni obtenir un Cookie d'Authentification 4) Alors que le premier navigateur a l'ASP.NET_SessionId il continue à travailler. De la minute où je supprimer ce cookie, il a le même problème que tous les autres navigateurs Je suis en train de travailler sur l'adresse ip (10.x.x.x) et localhost.

Mise à jour 2: Forcer la création de ASPNET_SessionId premier sur mon login_load page avant de l'authentification avec OWIN.

1) avant de m'authentifier avec OWIN je fais une Session aléatoire.Valeur du contenu sur ma page de connexion pour démarrer l'ASP.NET_SessionId 2) ensuite, je authentifier et à faire d'autres séances 3) les Autres navigateurs semblent maintenant travailler

Ce qui est bizarre. Je ne peux que conclure que cela a quelque chose à voir avec l'ASP et OWIN à penser qu'ils sont dans des domaines différents ou quelque chose comme ça.

Mise à jour 3 - comportement Étrange entre les deux.

Supplémentaires étrange comportement déterminé d'expiration de Owin et de la session de l'AEP est différent. Ce que je vois, c'est que mon Owin sessions de rester en vie plus longtemps que mes sessions de l'AEP à travers un mécanisme. Donc, lors de la connexion: 1.) J'ai un cookied en fonction d'authentification de session 2.) J'ai mis un peu de variables de session

Mes variables de session(2) "mourir" avant le owin cookie variable de session forces de re-connexion, ce qui provoque le comportement inattendu pendant toute mon application. (La personne est connecté, mais n'est pas vraiment connecté)

Mise à jour 3B -

Après quelques recherches, j'ai vu quelques commentaires sur une page qui disent que les "formes" d'authentification délai d'attente et le délai d'expiration de session doivent correspondre. Je pense normalement les deux sont en phase, mais pour quelque raison, les deux ne sont pas synchronisés.

Résumé des Solutions de contournement

1) Toujours créer une Session avant l'authentification. Fondamentalement, créer une session lorsque vous commencez la Session de l'application["solution de Contournement"] = 0;

2) [Expérimental] si vous persistez cookies assurez-vous que votre OWIN timeout / durée est plus longue que votre sessionTimeout dans votre site web.config (en test)

165voto

Tomas Dolezal Points 386

J'ai rencontré le même problème et de les remonter à la cause pour OWIN ASP.NET l'hébergement de mise en œuvre. Je dirais que c'est un bug.

Certains d'arrière-plan

Mes conclusions sont basées sur ces versions de montage:

  • Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • Microsoft.Owin.De l'hôte.SystemWeb, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • Système.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

OWIN utilise sa propre abstraction de travailler avec les Cookies de réponse (Microsoft.Owin.ResponseCookieCollection). Cette mise en œuvre directement roulés en-têtes de réponse de la collection et, en conséquence, les mises à jour de Set-Cookie - tête. OWIN ASP.NET hôte (Microsoft.Owin.De l'hôte.SystemWeb) encapsule le Système.Web.HttpResponse et c'est en-têtes de collection. Ainsi, lorsque de nouvelles cookie est créé par OWIN, réponse Set-Cookie - tête est modifié directement.

Mais ASP.NET utilise également sa propre abstraction de travailler avec les Cookies de réponse. Ce est exposée à nous en tant que Système.Web.HttpResponse.Les Cookies de propriété et mis en œuvre par classe scellée Système.Web.HttpCookieCollection. Cette mise en oeuvre ne les emballez pas de réponse Set-Cookie - tête directement, mais utilise quelques optimisations et de la poignée de notifications internes de se manifester, il a changé d'état à la réponse de l'objet.

Ensuite, il y a un point de retard dans la demande de vie où HttpCookieCollection changé d'état est testé (Système d'.Web.HttpResponse.GenerateResponseHeadersForCookies()) et les cookies sont sérialisées sur Set-Cookie - tête. Si cette collection est en quelque état, tout-tête Set-Cookie est tout d'abord effacé et recréé à partir de l'enregistrement de cookies dans la collection.

ASP.NET session de mise en œuvre utilise le Système.Web.HttpResponse.Les témoins de la propriété de stocker de l'ASP.NET_SessionId cookie. Il ya aussi une certaine optimisation de base dans ASP.NET l'état de session (module deSystème.Web.SessionState.SessionStateModule) mis en œuvre par le biais de propriété statique nommée s_sessionEverSet qui est tout à fait explicite. Si jamais vous stocker quelque chose à l'état de session dans votre application, ce module permettra de faire un peu plus de travail pour chaque demande.


Revenons à notre problème de connexion

Avec tous ces morceaux de vos scénarios peuvent être expliqués.

Cas 1 - Session n'a été défini

Système.Web.SessionState.SessionStateModule, s_sessionEverSet propriété est fausse. Aucun id de session sont générées par l'état de la session du module et du Système.Web.HttpResponse.Les témoins de la collection de l'état n'est pas détecté comme changé. Dans ce cas, OWIN des cookies sont envoyés correctement le navigateur et la connexion fonctionne.

Cas 2 - Session a été utilisé quelque part dans l'application, mais pas avant que l'utilisateur tente de s'authentifier

Système.Web.SessionState.SessionStateModule, s_sessionEverSet propriété est vraie. Id de Session sont générées par SessionStateModule, ASP.NET_SessionId est ajouté au Système.Web.HttpResponse.Les témoins de la collection, mais elle est retirée plus tard dans la demande de durée de vie que la session de l'utilisateur est en fait vide. Dans ce cas le Système.Web.HttpResponse.Les témoins de la collection de l'état est détecté comme changé et Set-Cookie - tête est d'abord débarrassée avant les cookies sont sérialisés à la valeur d'en-tête.

Dans ce cas, OWIN réponse cookies sont "perdus" et l'utilisateur n'est pas authentifié et est redirigé vers la page de connexion.

Cas 2 - Session est utilisée avant que l'utilisateur tente de s'authentifier

Système.Web.SessionState.SessionStateModule, s_sessionEverSet propriété est vraie. Id de Session sont générées par SessionStateModule, ASP.NET_SessionId est ajouté au Système.Web.HttpResponse.Les témoins. Grâce à l'optimisation interne au Système.Web.HttpCookieCollection et du Système.Web.HttpResponse.GenerateResponseHeadersForCookies() -tête Set-Cookie n'est PAS effacé , mais seulement mis à jour.

Dans ce cas, les deux OWIN les cookies d'authentification et de l'ASP.NET_SessionId cookies sont envoyés en réponse et la connexion fonctionne.


Problème plus général avec les cookies

Comme vous pouvez le voir, le problème est plus général et ne se limite pas à ASP.NET session. Si vous êtes l'hôte de OWIN par Microsoft.Owin.De l'hôte.SystemWeb et vous/quelque chose est directement à l'aide du Système.Web.HttpResponse.Les Cookies collection vous êtes à risque.

Par exemple cela fonctionne et les deux témoins sont correctement envoyées au navigateur...

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

    return View();
}

Mais cela ne veut pas et OwinCookie est "perdu"...

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

    return View();
}

Les deux testés à partir de VS2013, IISExpress et par défaut MVC modèle de projet.

47voto

Anders Abel Points 36203

En commençant par la grande analyse par @TomasDolezal, j'ai eu un coup d'oeil à la fois la Owin et le Système.Web source.

Le problème est que le Système.Web a son propre master de la source de l'information des cookies et ce n'est pas l'-tête Set-Cookie. Owin ne sait que sur l'-tête Set-Cookie. Une solution est de faire en sorte que tout les cookies définis par Owin sont également mis dans l' HttpContext.Current.Response.Cookies de la collecte.

J'ai fait un petit middleware (source, nuget) qui fait exactement cela, qui est destinée à être placée immédiatement au-dessus du cookie middleware d'enregistrement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X