使用 iPhone UIWebView 时的 Asp.Net 表单身份验证
Posted
技术标签:
【中文标题】使用 iPhone UIWebView 时的 Asp.Net 表单身份验证【英文标题】:Asp.Net Forms Authentication when using iPhone UIWebView 【发布时间】:2011-05-08 16:43:33 【问题描述】:我正在编写一个使用表单身份验证的 Asp.net MVC 2 应用程序,目前我的 iPhone 应用程序在通过 Web 进行身份验证/登录时遇到问题。我们开发了一个使用 UIWebView 控件的简单 iPhone 应用程序。在这个阶段,应用程序所做的只是导航到我们的 Asp.Net 网站。很简单,对吧?问题是,用户无法通过登录页面。复制步骤是:
打开 iPhone 应用程序。 应用导航到主页。 用户未通过身份验证,因此他们被重定向到登录屏幕/页面 用户输入了正确的用户名和密码。点击提交。 在服务器端,对用户进行身份验证,并使用 FormsAuthentication.GetAuthCookie 生成一个 cookie 并将其发送到客户端。 服务器发送重定向以将用户发送到正确的主页。但是用户随后被重定向BACK到登录屏幕!
我已经对此进行了一些广泛的调试,我所知道的是:
cookie 正在发送到客户端,客户端正在存储 cookie。在 iPhone 调试器中验证了这一点,并使用 Javsascript 在页面上显示 cookie 数据。 cookie 被发送回服务器。在 Visual Studio 调试器中验证了这一点。它是正确的 cookie(与设置的相同)。属性 User.Identity.IsAuthenticated 出于某种原因返回 false,即使 auth cookie 包含在 Request 对象中。我已验证 iPhone 应用已设置为接受 cookie,并且它们位于客户端上。
有趣的是:如果您在 iPhone 上打开 Safari 浏览器并直接访问我们的网站,它就可以正常工作。
它在 iPad 上也有相同的行为,因为它不会通过登录屏幕。这在模拟器和设备上重现。
同一个网站已经用 IE 7-8、Safari(Windows 版)、Blackberry、IEMobile 6.5、Phone 7 进行了测试,并且可以找到。唯一不起作用的情况是 iPhone 应用中的 UIWebView。
【问题讨论】:
您找到解决此问题的方法了吗?我也面临同样的问题... :( 是的,我们确实设法找到了解决方案。我会请解决问题的开发人员发布他的解决方案,因为他比我更了解。 请提供解决方案,因为我也面临同样的问题。谢谢。 【参考方案1】:我遇到了完全相同的问题,但使用的是另一台设备 (NokiaN8),并将问题追溯到 User-Agent。
IIS 使用正则表达式来匹配用户代理字符串。问题的根源在于它没有针对特定设备的任何匹配正则表达式,并且最终处于使用默认属性的最低匹配级别之一。 默认属性表示浏览器不支持cookies。
解决方案:
-
在您的 Web 项目中添加一个名为
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>
更多信息:Browser Definition File Schema
【讨论】:
奇怪的是,如果我们将 User-Agent 更改为“blah blah blah”,它实际上可以工作。只是 iPhone 中使用的内置 Web 浏览器视图失败的特定 User-Agent。似乎 IIS 服务器不仅默认使用未知浏览器,而且实际上阻塞了 User-Agent 字符串。 我们发现问题在于,在 ASP.Net 4.0 中,用户代理的解析是这样一种方式,即 UIWebView 控件被识别为“Mozilla”浏览器,因为有在用户代理中没有对 Safari 的引用。当我查看服务器上的各种 .browser 文件时,我发现包含 Mozilla 浏览器 (generic.browser) 匹配的文件包含我们找到的解决方案是创建一个文件 (generic.browser) 并包含此 xml,以告诉 Web 服务器“Mozilla”和默认浏览器设置都应该支持 cookie。
<browser refID="Mozilla" >
<capabilities>
<capability name="cookies" value="true" />
</capabilities>
</browser>
【讨论】:
感谢您提供样品。我能够使用它并与配置文件夹中的其他一些文件进行比较并获得我需要的东西。我不确定您是否可以使用与现有浏览器定义相同的名称,所以为了安全起见,我创建了 generic2.browser。再次感谢!!! 使用 cookies=true 添加默认条目解决了我的问题。 男人!!这解决了问题! Safari 浏览器根本没有存储表单身份验证持久性 cookie。请解释:您自己的帖子的解决方案 1 和 2 不起作用 - hanselman.com/blog/… 。但是“Mozilla”是如何工作的呢?因为 Mozilla 不是苹果,对吧? 继续之前的评论,它在关闭和打开浏览器后工作,因此它是持久的。但是,尽管我已将超时设置为 48 小时,但它只需要 30 分钟的超时时间。请问有什么想法吗? 仅供参考:隐私浏览模式也会导致这些症状【参考方案3】:这在 ASP.NET 4.5 中已修复,并且假定所有浏览器都支持 cookie,因此不需要额外的 .browser 文件。
【讨论】:
我已经尝试了此页面上的所有方法,并且我在 .NET 4.5 中运行,但它仍然无法正常工作。 ***.com/questions/24781648/…【参考方案4】:根据我所做的研究,您无法设置 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) 然后像这样使用它。 (连接委托将数据保存在可变数组中 然后在加载完成时使用其 loadData 方法手动设置 UIWebView)。
- (void)loadWithURLString:(NSString*)urlString
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
_connection = [NSURLConnection connectionWithRequest:request delegate:self];
[_connection start];
【讨论】:
解决了问题!谢谢,伙计! 补充答案,我发现 ASP.NET 对用户代理中的字符串“Mozilla”不满意,但是当它后面跟着字符串“Version/xx Safari”时没关系.这就是 UIWebView 提供的用户代理字符串失败,而移动 Safari 提供的用户代理字符串通过的原因。愚蠢的 ASP.NET... William,您对用户代理中“mozilla”的问题是正确的。如果您查看接受的答案,则有关于如何在服务器端解决此问题的信息。我们能够回滚所有涉及入侵用户代理的 iPhone 代码,因为服务器现在可以识别 cookie。 查看***.com/questions/478387/… 以更轻松地更改用户代理【参考方案5】:您是否指定了一个 标记中的 DestinationPageUrl?
您是否在 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 jar 并查看您的会话 cookie 是否真的存在?
Where are an UIWebView's cookies stored?
【讨论】:
感谢 ASP.NET 中的建议。我会试一试。回覆。 cookie,是的,它们已按照问题中的描述正确设置和发送。 我不知道 UIWebView 将 cookie 存储在哪里。我确实知道 ios 上的每个应用程序都有自己的缓存和 cookie 存储。是的,我已经确认 cookie 存储在设备上,并且它们也被发送回服务器。【参考方案6】:这种情况发生的原因显然与以下事实有关.
然而 MVC 路由系统显然错过了这种可能性,这显然是一个错误,因此它变得一团糟。
虽然添加带有自定义用户代理的.browser可以解决问题,但不能保证其他用户代理也可以解决,实际上我发现android的K9浏览器也有这个问题,并且因此,只有使用 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 路由将用户发送到一个错误页面,说明他的浏览器目前不受支持,并向带有用户代理的网站管理员发送警报以进行处理。
【讨论】:
以上是关于使用 iPhone UIWebView 时的 Asp.Net 表单身份验证的主要内容,如果未能解决你的问题,请参考以下文章
iPhone - UIWebView 在没有数据连接的情况下不调用 didFailLoadWithError