使用iPhone UIWebView的Asp.Net Forms身份validation
我正在写一个使用表单身份validation的Asp.net MVC 2应用程序,目前我在通过Web进行身份validation/login时遇到了iPhone应用程序的问题。 我们开发了一个使用UIWebView控件的简单iPhone应用程序。 在这个阶段,所有的应用程序都导航到我们的Asp.Net网站。 很简单,对吧? 问题是,用户无法越过login页面。 repro步骤是:
- 打开iPhone应用程序。
- 该应用程序导航到主页。
- 用户没有被authentication,所以他们被redirect到login屏幕/页面
- 用户input正确的用户名和密码。 点击提交。
- 在服务器端,用户通过身份validation,生成一个cookie,并使用FormsAuthentication.GetAuthCookie发送给客户端。
- 服务器发送redirect将用户发送到正确的主页。
但用户被redirect回login屏幕!
我已经做了一些广泛的debugging,我知道的是:
Cookie正在发送给客户端,客户端正在存储Cookie。 在iPhonedebugging器中validation了这一点,并使用Javsascript在页面上显示cookie数据。 该cookie正在被发送回服务器。 在Visual Studiodebugging器中validation了这一点。 这是正确的cookie(这是设置相同的)。 即使auth cookie包含在Request对象中,User.Identity.IsAuthenticated属性也会由于某种原因返回false。 我已经validationiPhone应用程序设置为接受cookie,并且它们在客户端上。
这是有趣的事情:如果你打开iPhone上的Safari浏览器,并直接进入我们的网站,它工作正常。
它在iPad上也有相同的行为,因为它不会超越login屏幕。 这个仿真器和设备上的repros。
这个网站已经testingIE 7-8,Safari(Windows),黑莓,IEMobile 6.5,电话7,它的工作发现。 唯一不适用的情况是iPhone应用程序中的UIWebView。
我有完全相同的问题,但与另一个设备(诺基亚N8),并将问题追溯到用户代理。
IIS使用正则expression式来匹配User-Agentstring。 问题的根源在于它没有任何匹配的特定设备的正则expression式,并且在使用Default属性的最低匹配级别之一结束。 默认属性表示浏览器不支持cookies。
解:
- 在名为
App_Browsers
的Web项目中添加一个文件夹(右键单击项目,select:Add > Add ASP.NET Folder > App_Browsers
)。 - 在该文件夹中添加文件(右键单击,select:
Add > New Item
)。 该文件可以有任何名称,但必须有.browser
结尾。 - 添加一个良好的匹配expression式和正确的function(或将更改添加到
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>
更多信息: 浏览器定义文件模式
我们find的解决scheme是创build一个文件(generic.browser),并包含这个XML告诉Web服务器,“Mozilla”和默认浏览器设置应该都支持cookies。
<browser refID="Mozilla" > <capabilities> <capability name="cookies" value="true" /> </capabilities> </browser>
这在ASP.NET 4.5中得到了解决,所有的浏览器都支持cookies,所以不需要额外的.browser文件。
从我做的研究来看,你无法设置用户代理的原因是UIWebView在发送请求之前设置了用户代理的值,也就是说,在你从你的代码发出请求之后。
解决这个问题的诀窍是使用一种叫做“方法调配”的方法,这是一种高级的,有潜在危险的Objective-C概念,用你提供的方法来replace标准方法。 最终的结果是,当你的请求被发送出去,并且框架代码添加了User-Agent的时候,它将被愚弄到你使用的方法。
下面解释我做了什么来实现这一点,但我不是Objective-C的专家,并build议你做一些研究,以熟悉自己的技术。 特别是那里有一个链接,比我说的更好,但是目前我找不到。
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允许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)然后像这样使用它。 (连接委托将数据保存在可变数组中,然后在完成加载时使用loadData方法手动设置UIWebView)。
- (void)loadWithURLString:(NSString*)urlString { NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; _connection = [NSURLConnection connectionWithRequest:request delegate:self]; [_connection start]; }
我有同样的问题,在这里研究和巩固一个完整的解决scheme(从上面的答案和其他线程): http : //www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/
-
你有没有在标记中指定DestinationPageUrl?
-
你有没有在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" />
最后,你有没有在cookiesjar看看,如果你的会话cookie实际存在?
UIWebView的cookie在哪里存储?
造成这种情况的原因显然与这样一个事实有关,即如果用户代理不知道,那么浏览器被认为不接受cookie(正如其他人所回答的那样),而是IIS将ASPXAUTH值放在URL中。
然而,MVC路由系统显然错过了这种可能性,这显然是一个错误,因此它正在变得混乱。
虽然用自定义用户代理添加.browser解决了这个问题,但并不能保证其他的用户代理也能解决,事实上我发现android的K9浏览器也有这个问题,如果有一个像elmeh这样的日志系统来追踪这样的错误,那么这只是一个解决scheme。
另一方面,如果所有的浏览器都接受cookies,那么添加一个默认值就会出现这个问题,这显然是IIS不这么认为的原因。
然而,除了明确地添加用户代理之外,还可以在global.asaxRegiterRoutes()方法中添加一个显式处理程序来忽略它,如下所示:
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路由将用户发送到一个错误页面,说明他的浏览器目前不受支持,并向用户代理发送一个警报给网站pipe理员处理。
- Asp.Net MVC中的DataAnnotations StringLength的文本框的maxlength属性
- 在angularjs中显示validation错误消息
- asp.netvalidation,以确保文本框具有整数值
- 什么是jQuery Unobtrusivevalidation?
- 最好的方法来在Javascript中的字母数字检查
- 更好的方法来检查variables为空或空string?
- 我应该如何为CodeIgniterselect一个authentication库?
- 提交后发生validation错误时,请保持p:对话框打开
- 重写jqueryvalidation插件的电子邮件地址validation