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];
}
Ответ 5
У меня была такая же точная проблема, она исследовала и консолидировала полное решение (сверху ответов и других потоков) здесь:
http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/
Ответ 6
Пример 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, чтобы отправить пользователя на страницу с ошибкой, объяснив, что его браузер в настоящий момент не поддерживается, и отправьте предупреждение веб-мастеру с помощью агента-пользователя для его обработки.