web-dev-qa-db-ja.com

iPhone UIWebView使用時のAsp.Netフォーム認証

フォーム認証を使用するAsp.net MVC 2アプリケーションを作成していますが、現在、Web経由の認証/ログインに関してiPhoneアプリケーションに問題があります。 UIWebViewコントロールを使用するシンプルなiPhoneアプリを開発しました。この段階で、アプリはすべて、Asp.Net Webサイトに移動します。シンプルでしょ?問題は、ユーザーがログインページを通過できないことです。再現手順は次のとおりです。

  • IPhoneアプリを開きます。
  • アプリはホームページに移動します。
  • ユーザーは認証されていないため、ログイン画面/ページにリダイレクトされます
  • ユーザーは正しいユーザー名とパスワードを入力します。送信をクリックします。
  • サーバー側では、ユーザーが認証され、FormsAuthentication.GetAuthCookieを使用してCookieが生成され、クライアントに送信されます。
  • サーバー送信はリダイレクトされ、ユーザーを正しいホームページに送信します。

しかし、ユーザーはその後リダイレクトされます バック ログイン画面に!

私はこれについていくつかの広範なデバッグを行ってきましたが、私が知っていることは:

Cookieはクライアントに送信されており、クライアントはCookieを保存しています。これをiPhoneデバッガーで検証し、Javsascriptを使用してページにCookieデータを表示しました。 Cookieはサーバーに送り返されています。 Visual Studioデバッガーでこれを確認しました。これは正しいCookieです(設定されたものと同じです)。認証CookieがRequestオブジェクトに含まれている場合でも、User.Identity.IsAuthenticatedプロパティは何らかの理由でfalseを返します。 iPhoneアプリがCookieを受け入れるように設定されており、それらがクライアント上にあることを確認しました。

おもしろいことは次のとおりです。iPhoneでSafariブラウザーを開いて、当社のサイトに直接アクセスすると問題なく動作します。

IPadでもログイン画面を通過しないという点で同じ動作をします。これは、エミュレーターおよびデバイスで再現されます。

この同じWebサイトは、IE 7-8、Safari(for Windows)、Blackberry、IEMobile 6.5、Phone 7でテストされており、正常に機能することが確認されています。 iPhoneアプリのUIWebViewです。

61
Brian Y

私たちが見つけた解決策は、ファイル(generic.browser)を作成し、このxmlを含めて「Mozilla」とデフォルトのブラウザ設定がすべてCookieをサポートする必要があることをWebサーバーに伝えることでした。

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

私はまったく同じ問題を抱えていましたが、別のデバイス(NokiaN8)で問題を追跡し、ユーザーエージェントにまでさかのぼりました。

IISは、正規表現を使用してUser-Agent文字列と照合します。問題の根本は、特定のデバイスに一致する正規表現がなく、デフォルトプロパティが使用された一致の最低レベルの1つになってしまったことでした。デフォルトのプロパティでは、ブラウザはクッキーをサポートしていませんでした。

解決策:

  1. App_Browsersという名前のWebプロジェクトにフォルダーを追加します(プロジェクトを右クリックして、Add > Add ASP.NET Folder > App_Browsersを選択します)。
  2. そのフォルダーにファイルを追加します(右クリックして、Add > New Itemを選択します)。ファイルには任意の名前を付けることができますが、.browserで終わる必要があります。
  3. 適切な一致表現と正しい機能を追加します(またはDefaultに変更を追加します)。

2つの例:

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

または、デフォルトを変更します。

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

詳細: ブラウザ定義ファイルスキーマ

44
Hunterwood

これはASP.NET 4.5で修正されており、すべてのブラウザーがCookieをサポートしていると想定されているため、追加の.browserファイルは必要ありません。

17
Scott Hanselman

私が行った調査から、User-Agentを設定できない理由は、UIWebViewがリクエストを送信する直前、つまりコードからリクエストを行った後、User-Agent値を設定しているためです。

この問題を回避するためのトリックは、「メソッドスウィズル」と呼ばれるものを使用することです。これは、標準メソッドを提供するメソッドと交換する、高度で潜在的に危険なObjective-Cの概念です。最終結果は、リクエストが送信され、フレームワークコードがUser-Agentを追加すると、指定したメソッドを使用してだまされることです。

以下はこれを実装するために何をしたかを説明していますが、私はObjective-Cの専門家ではないので、このテクニックに慣れるためにいくつかの研究を行うことをお勧めします。特に、ここで何が起こっているのかを私よりよく説明するリンクがそこにありましたが、現時点ではそれを見つけることができません。

1)NSObjectにカテゴリを追加して、スウィズルを許可します。

@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)NSMutableURLRequestをサブクラス化して、スウィズルを許可します。

@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)静的メソッドを呼び出して、メソッドを交換します。 didFinishLaunchingWithOptionsでこの呼び出しを行いました。

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

4)そして、このように使用しました。 (接続デリゲートは、データを可変配列に保存し、ロードが完了したら、loadDataメソッドを使用してUIWebViewを手動で設定します)。

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

私は同じ正確な問題を抱えていて、完全なソリューションを調査し、上記の回答と他のスレッドから統合しました: http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone -cookies /

3
Gautam Jain
  1. マークアップでDestinationPageUrlを指定しましたか?

  2. Web.configでdefaultURLを指定しましたか?

Web.configの例

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

DestinationPageUrlの例

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

最後に、Cookie jarを調べて、セッションCookieが実際に存在するかどうかを確認しましたか?

IWebViewのCookieはどこに保存されますか?

0

これが発生する理由は、ユーザーエージェントが不明な場合、ブラウザが(他の人が答えたように)Cookieを受け入れないと見なされ、代わりにIIS puts URLのASPXAUTH値。

ただし、MVCルーティングシステムは明らかにその可能性を見逃しており、これは明らかにバグであるため、めちゃくちゃになっています。

.browserにカスタムユーザーエージェントを追加すると問題は解決しますが、他のユーザーエージェントも解決されることを保証するものではなく、実際にAndroidまた、この問題があり、そのようなエラーを追跡するためにelmehなどのロギングシステムを持っている場合にのみ解決策です。

一方、デフォルトを追加すると、すべてのブラウザーがCookieを受け入れることが真実である場合に問題が発生します。これが、IISがそうと仮定しない理由です。

ただし、ユーザーエージェントを明示的に追加する以外に、global.asax RegiterRoutes()メソッドに明示的なハンドラーを追加して、次のように無視することができます。

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

ただし、この場合、カスタムルートハンドラーを作成する場合を除き、Cookieのない状況に一致するようにすべてのルートエントリをコピーする必要があります。

または、上記のCookieなしのルートを使用して、ブラウザーが現在サポートされていないことを説明するエラーページにユーザーを送信し、ユーザーエージェントでWebマスターにアラートを送信して処理することができます。

0
yoel halb