web-dev-qa-db-fra.com

Authentification Asp.Net Forms lors de l'utilisation de l'iPhone UIWebView

J'écris une application Asp.net MVC 2 qui utilise l'authentification par formulaire et actuellement j'ai un problème avec notre application iPhone en ce qui concerne l'authentification/connexion sur le Web. Nous avons développé une application iPhone simple qui utilise le contrôle UIWebView. À ce stade, l'application ne fait que naviguer sur notre site Web Asp.Net. C'est simple, non? Le problème est que l'utilisateur ne peut pas dépasser la page de connexion. Les étapes de repro sont les suivantes:

  • Ouvrez l'application iPhone.
  • L'application accède à la page d'accueil.
  • l'utilisateur n'est pas authentifié, il est donc redirigé vers l'écran/la page de connexion
  • L'utilisateur entre le nom d'utilisateur et le mot de passe corrects. clics soumettre.
  • côté serveur, l'utilisateur est authentifié et un cookie est généré et envoyé au client à l'aide de FormsAuthentication.GetAuthCookie.
  • Les envois du serveur sont redirigés pour envoyer l'utilisateur vers la page d'accueil correcte.

Mais l'utilisateur est ensuite redirigé ARRIÈRE à l'écran de connexion!

J'ai fait un débogage approfondi à ce sujet et ce que je sais, c'est:

Le cookie est envoyé au client et le client stocke le cookie. Vérifié dans le débogueur iPhone et également en utilisant Javsascript pour afficher les données des cookies sur la page. Le cookie est renvoyé au serveur. Vérifié cela dans le débogueur Visual Studio. C'est le bon cookie (c'est le même qui a été défini). La propriété User.Identity.IsAuthenticated renvoie false pour une raison quelconque, même si le cookie d'authentification est contenu dans l'objet Request. J'ai vérifié que l'application iPhone est configurée pour accepter les cookies et qu'ils sont sur le client.

Voici la chose amusante: cela fonctionne bien si vous ouvrez le navigateur Safari sur l'iPhone et accédez directement à notre site.

Il a également le même comportement sur l'iPad en ce sens qu'il ne dépasse pas l'écran de connexion. Cette repro sur les émulateurs et sur les appareils.

Ce même site Web a été testé avec IE 7-8, Safari (pour Windows), Blackberry, IEMobile 6.5, Phone 7 et il fonctionne trouver. La seule circonstance sur laquelle il ne fonctionne pas est l'UIWebView dans l'application iPhone.

61
Brian Y

La solution que nous avons trouvée était de créer un fichier (generic.browser) et d'inclure ce xml pour indiquer au serveur Web que "Mozilla" et les paramètres du navigateur par défaut devraient tous prendre en charge les cookies.

<browser refID="Mozilla" >
    <capabilities>
        <capability name="cookies"  value="true" />
    </capabilities>
</browser>
42
Brian Y

J'ai eu exactement le même problème, mais avec un autre appareil (NokiaN8), et j'ai également retracé le problème à l'agent utilisateur.

IIS utilise des expressions régulières pour correspondre à la chaîne User-Agent. La racine du problème était qu'il n'avait aucune expression régulière correspondante pour le périphérique spécifique, et s'est retrouvé dans l'un des niveaux de correspondance les plus bas, où les propriétés par défaut ont été utilisées. Les propriétés par défaut indiquent que le navigateur ne prend pas en charge les cookies.

Solution:

  1. Ajoutez un dossier dans votre projet Web nommé App_Browsers (cliquez avec le bouton droit sur le projet, choisissez: Add > Add ASP.NET Folder > App_Browsers).
  2. Ajoutez un fichier dans ce dossier (clic droit, choisissez: Add > New Item). Le fichier peut avoir n'importe quel nom, mais doit avoir le .browser se terminant.
  3. Ajoutez une bonne expression de correspondance et les capacités correctes (ou ajoutez des modifications à Default).

Deux exemples:

<browsers>
  <browser id="NokiaN8" parentID="Mozilla">
    <identification>
      <userAgent match="NokiaN8" />
    </identification>
    <capabilities>
      <capability name="browser" value="NokiaN8" />
      <capability name="cookies" value="true" /> 
    </capabilities> 
  </browser> 
</browsers>

Ou modifiez la valeur par défaut:

<browsers>
  <browser refID="Default"> 
    <capabilities> 
      <capability name="cookies" value="true" /> 
    </capabilities>
  </browser>
</browsers>

Plus d'informations: Schéma de fichier de définition du navigateur

44
Hunterwood

Ce problème est résolu dans ASP.NET 4.5 et tous les navigateurs sont supposés prendre en charge les cookies, de sorte que le fichier .browser supplémentaire ne sera pas nécessaire.

17
Scott Hanselman

D'après les recherches que j'ai faites, la raison pour laquelle vous ne pouvez pas définir l'agent utilisateur est que l'UIWebView définit la valeur de l'agent utilisateur juste avant d'envoyer la demande, c'est-à-dire après avoir effectué votre demande à partir de votre code .

L'astuce pour contourner ce problème est d'utiliser quelque chose appelé "méthode swizzling", un concept Objective-C avancé et potentiellement dangereux qui permute une méthode standard avec celle que vous fournissez. Le résultat final est que lorsque votre demande est envoyée et que le code de structure ajoute l'agent utilisateur, il sera trompé en utilisant la méthode que vous avez fournie.

Ce qui suit explique ce que j'ai fait pour mettre en œuvre cela, mais je ne suis pas un expert d'Objectif-C et je vous suggère de faire quelques recherches pour vous familiariser avec la technique. En particulier, il y avait un lien qui expliquait mieux que moi ce qui se passait ici, mais pour le moment je ne le trouve pas.

1) Ajoutez une catégorie sur NSObject pour permettre le swizzling.

@interface NSObject (Swizzle)

+ (BOOL) swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector;

@end

@implementation NSObject (Swizzle)


+ (BOOL) swizzleMethod:(SEL) origSelector withMethod:(SEL)newSelector
{
    Method origMethod= class_getInstanceMethod(self, origSelector);
    Method newMethod= class_getInstanceMethod(self, newSelector);

    if (origMethod && newMethod)
    {
        if (class_addMethod(self, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        {
            class_replaceMethod(self, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        }
        else {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}
@end

2) Sous-classe NSMutableURLDemande d'autoriser le swizzle:

@interface NSMutableURLRequest (MyMutableURLRequest)

+ (void) setupUserAgentOverwrite;

@end
@implementation NSMutableURLRequest (MyMutableURLRequest)

- (void) newSetValue:(NSString*)value forHTTPHeaderField:(NSString*)field
{
    if ([field isEqualToString:@"User-Agent"])
    {
        value = USER_AGENT;  // ie, the value I want to use.
    }
    [self newSetValue:value forHTTPHeaderField:field];
}
+ (void) setupUserAgentOverwrite
{
    [self swizzleMethod:@selector(setValue:forHTTPHeaderField:) 
             withMethod:@selector(newSetValue:forHTTPHeaderField:)];

}

@end

3) Appelez la méthode statique pour échanger la méthode. J'ai fait cet appel dans didFinishLaunchingWithOptions:

// Need to call this method so that User-Agent get updated correctly:
[NSMutableURLRequest setupUserAgentOverwrite];

4) Et puis utilisé comme ça. (Le délégué de connexion enregistre les données dans un tableau modifiable, puis définit manuellement l'UIWebView à l'aide de sa méthode loadData lorsqu'il termine le chargement).

- (void)loadWithURLString:(NSString*)urlString
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
_connection = [NSURLConnection connectionWithRequest:request delegate:self];
[_connection start];
}
5
Jack

J'ai eu le même problème exact, recherché et consolidé une solution complète (à partir des réponses ci-dessus et d'autres fils) ici: http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone -cookies /

3
Gautam Jain
  1. Avez-vous spécifié une DestinationPageUrl dans le balisage?

  2. Avez-vous spécifié l'URL par défaut dans web.config?

Exemple web.config

<authentication mode="Forms">
     <forms loginUrl="~/Login.aspx" defaultUrl="~/CustomerArea/Default.aspx"/>
</authentication>

Exemple DestinationPageUrl

 <asp:Login ID="Login" runat="server" DestinationPageUrl="~/Secret/Default.aspx" />

Enfin, avez-vous regardé dans le pot de cookies et vu si votre cookie de session existe réellement?

Où sont stockés les cookies d'un UIWebView?

0
Maxim Gershkovich

La raison de ce phénomène est apparemment liée au fait que si l'agent utilisateur n'est pas connu, le navigateur est supposé ne pas accepter les cookies (comme d'autres l'ont répondu), et à la place IIS met la valeur ASPXAUTH dans l'URL.

Cependant, le système de routage MVC a apparemment manqué cette possibilité, qui est clairement un bogue, et donc il est foiré.

Bien que l'ajout du .browser avec un agent utilisateur personnalisé résout le problème, cela ne garantit pas que d'autres agents utilisateurs seront également résolus, et en fait, j'ai trouvé le navigateur K9 pour le Android a également ce problème, et en tant que tel, ce n'est une solution que si l'on dispose d'un système de journalisation tel que elmeh pour localiser ces erreurs.

D'un autre côté, l'ajout d'une valeur par défaut soulève la question s'il est vrai que tous les navigateurs acceptent les cookies, ce qui est apparemment la raison pour laquelle IIS ne le suppose pas.

Cependant, en plus d'ajouter explicitement les agents utilisateurs, on peut ajouter dans la méthode global.asax RegiterRoutes () un gestionnaire explicite pour l'ignorer, comme suit:

         routes.MapRoute(
            "CookieLess", // Route name
            "(F({Cookie}))/{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

Cependant, dans ce cas, il faudra copier toutes les entrées de route pour correspondre à la situation sans cookie, sauf si l'on est sur le point d'écrire un gestionnaire de route personnalisé.

Ou nous pouvons utiliser la route sans cookie ci-dessus pour envoyer l'utilisateur à une page d'erreur expliquant que son navigateur n'est pas pris en charge pour le moment, et envoyer une alerte au webmestre avec l'agent utilisateur pour le gérer.

0
yoel halb