Asp.Net Forms Authentication при использовании iPhone UIWebView

Я пишу приложение Asp.net MVC 2, которое использует проверку подлинности с помощью форм, и в настоящее время у меня проблема с нашим приложением iPhone в отношении аутентификации/входа в сеть. Мы разработали простое приложение для iPhone, которое использует элемент управления UIWebView. На этом этапе все приложение - это переход на наш сайт Asp.Net. Простой, не так ли? Проблема в том, что пользователь не может пройти страницу входа. Этапы воспроизведения:

  • Откройте приложение для iPhone.
  • Приложение переходит на домашнюю страницу.
  • пользователь не аутентифицирован, поэтому он перенаправляется на экран входа/страницу
  • Пользователь вводит правильное имя пользователя и пароль. клики submit.
  • на стороне сервера, пользователь аутентифицируется и cookie генерируется и отправляется клиенту с использованием FormsAuthentication.GetAuthCookie.
  • Сервер отправляет перенаправление, чтобы отправить пользователя на правильную домашнюю страницу.

Но затем пользователь перенаправляется НАЗАД на экран входа в систему!

Я сделал довольно обширную отладку по этому поводу, и я знаю:

cookie отправляется клиенту, а клиент хранит файл cookie. Проверено это в отладчике iPhone, а также с помощью Javsascript для отображения данных cookie на странице. Куки файлы отправляются обратно на сервер. Проверено это в отладчике Visual Studio. Это правильный файл cookie (это тот, который был установлен). Свойство User.Identity.IsAuthenticated по какой-то причине возвращает false, хотя файл cookie auth содержится в объекте Request. Я подтвердил, что приложение iPhone настроено на прием файлов cookie, и они находятся на клиенте.

Вот забавная вещь: она отлично работает, если вы открываете браузер Safari на iPhone и отправляетесь на наш сайт напрямую.

У него такое же поведение и на iPad, что он не проходит мимо экрана входа в систему. Это воспроизводится на эмуляторах и на устройствах.

Этот же веб-сайт был протестирован с IE 7-8, Safari (для Windows), Blackberry, IEMobile 6.5, Phone 7 и работает. Единственное обстоятельство, что он не работает, - это UIWebView в приложении iPhone.

Ответ 1

Мы обнаружили, что мы создали файл (generic.browser) и включили этот xml, чтобы сообщить веб-серверу, что "Mozilla" и настройки браузера по умолчанию должны поддерживать файлы cookie.

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

Ответ 2

У меня была точно такая же проблема, но с другим устройством (NokiaN8), а также прослеживалась проблема с User-Agent.

IIS использует регулярные выражения для сопоставления с строкой User-Agent. Корень проблемы состоял в том, что у нее не было подходящих регулярных выражений для конкретного устройства и она оказалась на одном из самых низких уровней соответствия, где использовались свойства Default. В свойствах по умолчанию указано, что браузер не поддерживает файлы cookie.

Решение:

  • Добавьте папку в свой веб-проект с именем App_Browsers (щелкните правой кнопкой мыши проект, выберите: Add > Add ASP.NET Folder > App_Browsers).
  • Добавьте файл в эту папку (щелкните правой кнопкой мыши, выберите: Add > New Item). Файл может иметь любое имя, но должен иметь завершение .browser.
  • Добавьте хорошее соответствие и правильные возможности (или добавьте изменения в Default).

Два примера:

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

Дополнительная информация: Схема файлов браузера

Ответ 3

Это исправлено в ASP.NET 4.5, и предполагается, что все браузеры поддерживают файлы cookie, поэтому дополнительный файл .browser не понадобится.

Ответ 4

Из проведенного мной исследования причина, по которой вы не можете установить User-Agent, заключается в том, что UIWebView устанавливает значение User-Agent непосредственно перед отправкой запроса, то есть после того, как вы сделали запрос от вашего кода.

Трюк, чтобы обойти эту проблему, - это использовать что-то под названием "swizzling", передовую и потенциально опасную концепцию Objective-C, которая заменяет стандартный метод с тем, который вы предоставляете. Конечным результатом является то, что когда ваш запрос отправляется, а код рамки добавляет User-Agent, он будет обманут в использовании метода, который вы предоставили.

Ниже объясняется, что я сделал, чтобы реализовать это, но я не эксперт Objective-C и предложил бы вам провести некоторое исследование, чтобы ознакомиться с этой техникой. В частности, там была ссылка, объясняющая лучше меня, что здесь происходит, но на данный момент я не могу ее найти.

1) Добавьте категорию в NSObject, чтобы разрешить 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) Подкласс NSMutableURLRequest, чтобы разрешить 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) Вызовите статический метод для замены метода. Я сделал этот звонок в файле didFinishLaunchingWithOptions:

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

4) И затем использовал его вот так. (Делегат соединения сохраняет данные в изменяемом массиве а затем вручную устанавливает UIWebView с использованием метода loadData, когда он заканчивает загрузку).

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

Ответ 6

  • Вы указали DestinationPageUrl в разметке?

  • Вы указали defaultURL в web.config?

Пример 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 и увидели, существует ли ваш файл cookie сессии?

Где хранятся файлы cookie UIWebView?

Ответ 7

Причина этого происходит, по-видимому, связана с тем фактом, что если пользовательский агент неизвестен, предполагается, что браузер не принимает файлы cookie (как ответили другие), а вместо этого IIS помещает значение ASPXAUTH в URL-адрес.

Однако система маршрутизации MVC, по-видимому, пропустила эту возможность, что, очевидно, является ошибкой, и поэтому она запуталась.

При добавлении .browser с настраиваемым пользовательским агентом решает проблему, это не гарантирует, что другие пользовательские агенты также будут решены, и на самом деле я обнаружил, что браузер K9 для 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, чтобы отправить пользователя на страницу с ошибкой, объяснив, что его браузер в настоящий момент не поддерживается, и отправьте предупреждение веб-мастеру с помощью агента-пользователя для его обработки.