UIWebView 中的 Facebook 身份验证不会重定向回我网站上要求身份验证的原始页面

Posted

技术标签:

【中文标题】UIWebView 中的 Facebook 身份验证不会重定向回我网站上要求身份验证的原始页面【英文标题】:Facebook authentication in a UIWebView does not redirect back to original page on my site asking for auth 【发布时间】:2011-11-06 03:35:38 【问题描述】:

在我们的 ios 应用程序中,我们有一个 UIWebView,它显示我们域上的 Web 内容,它有一个 Facebook 评论模块。评论模块要求用户使用 facebook 登录。当用户点击登录按钮时,他们会进入登录流程,但永远不会重定向回我们的页面。他们最终出现在一个 FB 拥有的页面上,该页面只是告诉用户“您现在已登录”。

复制步骤:

    在 iOS 应用中创建 UIWebView,并在托管在您拥有的某个域(例如 http://foo.com/test.htm)的页面上托管 Facebook 评论模块。 点击评论模块上的登录按钮,您将被重定向到 FB 登录。 使用有效的 FB 凭据登录并观察会发生什么。

在您登录后(第 3 步),我希望在成功验证后,您会被重定向回原始页面(例如 http://foo.com/test.htm),以便您继续互动。然而,这并没有发生。

相反,您在一个 FB 拥有的页面上,该页面仅显示“您现在已登录”之类的内容,而您被困在那里。不会发生重定向。

这确实是一个错误,还是我应该做些什么来确保重定向发生?

【问题讨论】:

如果您使用 OS X Safari 重现所有内容,您会得到相同的行为吗?换句话说,您是否确认这是 UIWebView 问题而不是您的其他方法的问题?如果您确认它在常规网络浏览器中运行良好,请将您的代码发布在您实例化并加载 UIWebView 的位置,以便我们查看您在其上设置的属性等。 我没有 OS X,但在 Safari 窗口上它不能重现。也就是说,加载带有 FB 未经身份验证状态的页面,单击评论插件中的评论按钮,弹出一个新的 safari 窗口,让我登录 FB,当我登录时它会关闭,原来的知道我已登录。但是,我怀疑这与我使用桌面 safari 时 FB 登录窗口在弹出窗口中的事实有关。在嵌入式 UIWebView 中,你不能做弹出窗口。在我上面的复制步骤中,您会看到 Facebook 被重定向到 FB 拥有的页面,而我没有机会做任何事情。 如果有人还在寻找 - 这有效 - ***.com/a/34777695/815929 【参考方案1】:

如果您只是支持 iOS 8 及更高版本,则可以使用 WKWebView,它已经实现了 @kabuko 描述的功能:

// Container view including the main WKWebView
var container : UIView?
var popupWebView : WKWebView?

override func viewDidLoad() 
    super.viewDidLoad()

    let prefs = WKPreferences()
    prefs.javascriptEnabled = true
    // allow facebook to open the login popup
    prefs.javaScriptCanOpenWindowsAutomatically = true

    let config = WKWebViewConfiguration()
    config.preferences = prefs

    webView = WKWebView(frame: container.frame, configuration: config)
    webView?.UIDelegate = self
    webView?.navigationDelegate = self


// callback if the content of the webView wants to create a new window
func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? 
    // create new popup webview and add it to the view hierarchy
    popupWebView = WKWebView(frame: container.frame, configuration: configuration)
    container.addSubview(popupWebView!)
    return popupWebView


func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) 
    // if the main webView loads a new page (e.g. due to succesful facebook login)
    // remove the popup
    if (popupWebView != nil) 
        popupWebView?.removeFromSuperview()
        popupWebView = nil
    

【讨论】:

这里的popupWebView是什么? createWebViewWithConfiguration方法中生成的一个新的WKWebView实例。此 Web 视图用于显示 Facebook 登录的“新窗口”。我将更新答案以使这一点更清楚。 非常感谢。这应该是新的响应,因为它更容易。只是一件事,你忘了webView?.UIDelegate = self 谢谢,你是对的。我只是将它添加到代码sn-p中。 这不会检测到 Google/Facebook/etc.. 登录弹出窗口/窗口。我试过了,它不起作用。它确实检测到基本的外部网站链接,但是当按下Login with Facebook 按钮时,它只会在当前WKWebView 中加载Facebook 登录页面。有什么解决办法吗?【参考方案2】:

如果您将其他网站的 FB 登录(例如 Groupon)加载到 UIWebView 中,我已经看到类似的情况发生。如果这是同样的问题(我认为是), 是因为 Facebook 在弹出窗口中打开了您所怀疑的登录窗口。在普通浏览器上发生的情况是打开另一个窗口(弹出窗口)进行登录,然后当用户登录时,该登录窗口与原始窗口通信以表示它已登录。他们可能使用 EasyXDM 或类似的东西.似乎有几层沟通策略,包括 Flash 和postMessage

在 iOS(和 android)上,这应该意味着它最终会与 postMessage 通信。如果您跟踪通过您的 UIWebView 的 URL,您应该会在结尾处看到类似这样的内容:

https://s-static.ak.fbcdn.net/connect/xd_proxy.php#<lots of stuff>&relation=opener&transport=postmessage&<lots more stuff>

UIWebView 不支持多个窗口,因此它不能postMessage 回到您的原始页面,因为它不再被加载。您可以做的是检测UIWebView 何时尝试加载 FB 登录页面并将其加载到单独的UIWebView 中。现在您有两个窗口可以使用。

不幸的是,这仍然不够,因为当 FB 页面上的 JavaScript 尝试运行 window.opener.postMessagewindow.parent.postMessage 时,它不起作用,因为 window.parentwindow.opener 未设置为适当的窗口。我不知道在 iOS 中执行此操作的好方法(相比之下,Android 为此提供了适当的 API)。

我解决这个问题的方法是破解一个 JavaScript 对象来包装这些调用。比如:

window.opener=;
window.opener.postMessage = function(data,url) 
    // signal your code in objective-c using some strategy
;
window.parent = window.opener;

有几种方法可以从 JavaScript 调用 Objective-C,包括 this one from the official docs。您可以将此代码注入我之前使用stringByEvaluatingJavaScriptFromString: 提到的那个静态FB 登录页面。我找不到执行此操作的好时机,所以我只是在页面加载后注入它并调用 doFragmentSend(),这是该静态页面上通常在正文加载时调用的 FB JavaScript 方法。

所以现在我们需要做的就是通过调用postMessage 将此数据传递到原始UIWebView。它看起来像这样:

NSString *post = [NSString stringWithFormat:@"window.postMessage('%@', '*');", data];
[webView stringByEvaluatingJavaScriptFromString:post];

如果您现在还没有注意到,这是一个非常混乱的 hack,除非您别无选择,否则我可能不会推荐它,但它对我有用。

【讨论】:

我有一个问题。您如何在页面中输入window.opener=; window.opener.postMessage = function(data,url) // signal your code in objective-c using some strategy ; window.parent = window.opener; 代码? 该代码块下方的段落描述了如何注入该代码。【参考方案3】:

我遇到了同样的问题。我发现,在 Facebook 登录后 UIWebView 组件是空的,里面没有 html 代码。我通过检查 webViewDidFinishLoad 函数上的 UIWebView 组件的内容解决了这个问题,并在我检测到 Facebook 登录导致白色(空屏)时重新加载其内容:

- (void)webViewDidFinishLoad:(UIWebView *)webView 
    if ( [[webView1 stringByEvaluatingJavaScriptFromString:
           @"document.body.innerHTML"] isEqualToString:@""] ) 
        [webView1 loadRequest:request]; //Define request as you want
    

【讨论】:

嘿,我知道这是一篇旧帖子,但这可能是我查询的解决方案。你能分享在request 中放入什么[webView1 loadRequest:request]。抱歉,我是 iOS 新手 @ShanilSoni:你知道什么是请求吗?? @szpetip:请您说明一下请求是什么,并附上样本? @rAzOr 不,我没有。请分享。【参考方案4】:

目前在移动端,浏览器默认不支持多窗口。 另一种解决方案是监视来自 facebook 的成功重定向,例如 “close_popup.php?reload=https://”并重新加载页面。 还要确保在登录请求之前保留 facebook 评论值,以便可以再次将其放入评论框中。

【讨论】:

以上是关于UIWebView 中的 Facebook 身份验证不会重定向回我网站上要求身份验证的原始页面的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UIWebView 中访问公共 Facebook 个人资料

facebook怎么验证?

使用 Facebook iOS SDK 登录 UIWebView

是否可以使用 Ionic 实现一键式 Facebook 登录?

Facebook iOS SDK 登录原生和 UIWebView 登录

在 iOS WebView 中添加 Facebook 的 Like 按钮