2

J'utilise l'authentification de formulaires personnalisés pour une application asp.net MVC, et j'ai des problèmes avec certains utilisateurs apparemment ne pas avoir de cookies. La méthode d'authentification des formulaires personnalisés que nous utilisons est similaire à celle-ci: custom forms authentication. Essentiellement, nous créons un principal personnalisé et l'identité, la sérialisation, et le stocker dans la propriété UserData du FormsAuthenticationTicket:.net mvc quelques utilisateurs manquant cookies

Connexion

MyCustomPrincipal principal = new MyCustomPrincipal(user); 
DateTime expiration = DateTime.Now.AddMinutes(30); 

FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
       1, 
       u.Username, 
       DateTime.Now, 
       expiration, 
       true, 
       JsonConvert.SerializeObject(principal)); 

HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket)); 
cookie.Expires = expiration; 

Response.Cookies.Set(cookie); 

Nous saisissons alors le cookie auth en cas Application_AuthenticateRequest de Global .asax.

global.asax - Application_AuthenticateRequest

// Get the authentication cookie 
string cookieName = FormsAuthentication.FormsCookieName; 
HttpCookie authCookie = Context.Request.Cookies[cookieName]; 

// If the cookie can't be found, don't issue the ticket 
if (authCookie == null) return; 

// Get the authentication ticket and rebuild the principal 
// & identity 
FormsAuthenticationTicket authTicket = 
      FormsAuthentication.Decrypt(authCookie.Value); 

MyCustomPrincipal userPrincipal = new MyCustomPrincipal(authTicket.UserData); 
DateTime expiration = DateTime.Now.AddMinutes(30); 

FormsAuthenticationTicket newAuthTicket = new FormsAuthenticationTicket(
       1, 
       ((MyCustomIdentity)userPrincipal.Identity).Username, 
       DateTime.Now, 
       expiration, 
       true, 
       JsonConvert.SerializeObject(userPrincipal)); 



authCookie.Value = FormsAuthentication.Encrypt(newAuthTicket); 
authCookie.Expires = expiration; 

HttpContext.Current.Response.Cookies.Set(authCookie); 

Context.User = userPrincipal; 

web.config

<authentication mode="Forms"> 
    <forms loginUrl="~/Home/Index" timeout="29" name="MYFORMSAUTH" cookieless="UseCookies"/> 
</authentication> 

Toutefois, cela fonctionne très bien pour la grande majorité des utilisateurs, il y a des utilisateurs qui semblent être obtenir aucun ensemble de cookie d'autorisation. J'ai fait quelques tests pour ajouter plus d'informations à mes journaux d'erreur Elmah pour voir si je pourrais en savoir plus sur le problème. En premier lieu, j'ai essayé de mettre en place des cookies de test avant et après le paramétrage du authcookie dans la méthode Login. Ces cookies et non apparaissent dans les journaux Elmah, il semble donc que l'ajout de cookies de toute sorte dans cette méthode ne fonctionne pas. Cependant, il y a d'autres cookies dans les journaux, y compris le ASP.NET_SessionId, un cookie de Google Analytics, et parfois il y a même d'autres cookies que j'ai mis à d'autres endroits dans l'application (probablement d'une session précédente)

Deuxièmement, j'ai essayé d'ajouter quelques informations à la session à partir de l'action de connexion, et de l'inclure dans le journal des erreurs si le authcookie n'a pas été trouvé sur l'action suivante. J'ai inclus la longueur du cookie (la longueur du nom + la longueur de la valeur chiffrée) ainsi que l'heure de la tentative de connexion. Ces deux éléments sont ajoutés uniquement si les informations d'identification de l'utilisateur sont valides et que l'application tente d'ajouter le cookie d'authentification. I do voir ces valeurs dans les journaux d'erreurs en cours de production. La longueur est toujours supérieure à 0, et je n'ai pas vu plus grand qu'environ 2300, donc je ne pense pas que la taille soit un problème. Et la tentative de connexion est identique à l'heure à laquelle l'erreur s'est produite. Les variables de session doivent donc avoir été définies immédiatement avant que l'erreur ne se produise (les cookies ont disparu).

Quelques notes plus -

  • Il ne semble pas être un navigateur en particulier qui semble être la cause de l'erreur plus (bien qu'il soit possible, il se produit plus sur les navigateurs mobiles)
  • Encore une fois , le site semble fonctionner pour la grande majorité des utilisateurs, et bien sûr nous ne pouvons pas reproduire le problème
  • Depuis que je ne vois pas les cookies de test, je suppose que pour une raison quelconque pas de cookies sont en cours de définition à partir de la connexion méthode à ce moment-là (même si je peux voir d'autres cookies mis en Le référant http dans les logs d'elmah est généralement défini sur la page de connexion, ce qui implique que les utilisateurs ne vont probablement pas sur la page incriminée sans se connecter (au moins une partie du temps) - l'état de les variables de session semblent soutenir cette hypothèse
  • Je vois souvent plusieurs de ces erreurs dans une rangée (séparées par une minute ou plus) - ce qui implique que le problème n'est pas résolu avec des tentatives de connexion répétées (je ne sais pas pourquoi il serait be)
  • Il semble que les utilisateurs qui ont ce problème continuent d'avoir le problème. En d'autres termes, il ne semble pas être "chance du tirage" - mais quelque chose soit avec le compte de l'utilisateur (que la variable de longueur de cookie implique qu'il sérialise correctement), soit avec le navigateur client.
  • J'ai entendu parler d'au moins un utilisateur qui pouvait se connecter sur un appareil mobile, mais pas sur son bureau
  • Au total, le site utilise probablement une dizaine de cookies (y compris tous les différents cookies de test qui ont été ajouté) - avant d'ajouter les cookies de test, il a utilisé environ 4, y compris le cookie auth. En outre, lorsque le bogue se produit, il semble y avoir seulement 2 ou 3 cookies dans la requête, donc je ne pense pas que le nombre de cookies soit un problème.

À ce stade, je suis prêt à essayer presque n'importe quoi. J'ai essayé de configurer l'identité personnalisée stockée dans la session en tant que sauvegarde, mais je n'ai pas réussi à la faire fonctionner, donc si quelqu'un a des idées sur la façon de l'implémenter (si possible), ce serait apprécié (si ce n'est pas le cas Je peux l'enlever). Désolé pour les murs de texte, mais je voulais juste souligner tous les problèmes potentiels que nous avons étudiés et probablement exclu.

EDIT

Il semble qu'il peut y avoir un autre problème potentiellement liés. Je vois des journaux d'erreurs qui me portent à croire que l'attribut "IsAuthenticated" de certaines identités est défini sur false alors qu'il ne devrait pas l'être. Nous initialisons this à false et le définissons à true une fois que l'utilisateur a répondu à une question de sécurité. Lorsque nous l'avons défini sur true, il doit mettre à jour le principe et le ticket/cookie d'authentification. Je ne suis pas sûr que cela se produise à cause de la façon dont je désérialise le principe de la coutume ou non.

Répondre

0

La mise en cache côté serveur est-elle activée? est je me souviens exactement j'avais un problème similaire et la cause était la mise en cache côté serveur (mal configuré) et le code côté serveur n'a pas été exécuté mais le client atteint la page. en plus de mon côté il y avait un bug (iis bug sur la mise en cache activée sur la page dynamique) que dans certaines situations le cookie de session est envoyé à plus de 1 client et cela provoque un résultat inattendu.

Ceci peut expliquer votre comportement de non-journalisation et le cookie absent du client.

Cordialement

+0

Je ne pense pas que nous utilisons une mise en cache côté serveur, du moins pas en ce qui concerne les sessions utilisateur ou les cookies. Je ne suis pas aussi familier avec IIS, donc je ne suis pas sûr du genre de choses qui sont faites automatiquement. Je pense que les problèmes que vous décrivez causeraient probablement des problèmes avec les utilisateurs au hasard, par opposition aux mêmes utilisateurs quelque peu régulièrement (comme le suggèrent certains des journaux d'erreurs). Cependant, nous examinerons certainement ces possibilités. – Neophyte

0

Je suis en quelque sorte donné et décidé d'utiliser la session pour stocker mon principal et vérifier quand je ne vois pas le cookie d'authentification. Je peux le faire un peu facilement en créant un attribut Authorize personnalisé, et en vérifiant la session là. Je ne l'ai pas encore fait passer en production, donc je ne suis pas sûr à 100% que cela va contourner le problème, mais des tests préliminaires suggèrent que cela suffira.

CustomAuthorizeAttribute

public class MyCustomAuthorizeAttribute : AuthorizeAttribute 
{ 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     // Get the authentication cookie 
     string cookieName = FormsAuthentication.FormsCookieName; 
     HttpCookie authCookie = HttpContext.Current.Request.Cookies[cookieName]; 

     // If the cookie can be found, use the base authentication 
     if (authCookie != null) 
     { 
      base.OnAuthorization(filterContext); 
     } 
     else 
     { 
      // The cookie is not found, check the session for the principal 

      var p = HttpContext.Current.Session[FormsAuthentication.FormsCookieName]; 

      if (p != null) 
      { 
       // there is a principal object in the session 
       MyCustomPrincipal principal = (MyCustomPrincipal)p; 

       HttpContext.Current.User = principal;     

       // we've loaded the principal, now just do the base authorization 
       base.OnAuthorization(filterContext); 

      } 
      else 
      { 
       // there is no principal object in the cookie or the session, the user is not authenticated 
       HandleUnauthorizedRequest(filterContext); 
      } 

     } 
    }  
} 

Une fois que nous avons fixé le principal courant en utilisant correctement l'attribut authorize personnalisé, nous pouvons alors il suffit d'utiliser l'autorisation de base, donc nous n'avons pas à vous soucier de la mise en œuvre de cette fonctionnalité nous-mêmes. L'autorisation de base doit vérifier le principal actuel et autoriser en fonction de cela. Je ne vais pas marquer cela comme une réponse, parce que cela ne résout pas vraiment le problème sous-jacent, mais je pensais que je fournirais une solution de rechange potentielle au cas où quelqu'un d'autre trébucherait sur un problème similaire.

Questions connexes