Проверка подлинности Asp.Net Forms при использовании iPhone UIWebView

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

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

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

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

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

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

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

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

7 ответов

Решение

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

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

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

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

Решение:

  1. Добавьте папку в свой веб-проект с именем App_Browsers (щелкните правой кнопкой мыши проект, выберите: Add > Add ASP.NET Folder > App_Browsers).
  2. Добавить файл в эту папку (щелкните правой кнопкой мыши, выберите: Add > New Item). Файл может иметь любое имя, но должен иметь .browser окончание.
  3. Добавьте подходящее выражение и правильные возможности (или внесите изменения в 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>

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

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

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

Хитрость, чтобы обойти эту проблему, состоит в том, чтобы использовать то, что называется "метод перебора", продвинутую и потенциально опасную концепцию 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];
}

У меня была точно такая же проблема, я исследовал и собрал полное решение (ответы сверху и другие темы) здесь: http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/

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

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

  2. Вы указали 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?

Другие вопросы по тегам