Подтвердить что ты не робот

Проверка подлинности Facebook в UIWebView не перенаправляет обратно на исходную страницу моего сайта, запрашивая авторизацию

В нашем приложении iOS у нас есть UIWebView, который показывает веб-контент в нашем домене с модулем комментариев Facebook. Модуль комментариев требует, чтобы пользователь входил в facebook. Когда пользователь нажимает кнопку входа в систему, они проходят через поток входных сигналов, но никогда не перенаправляются обратно на нашу страницу. Они попадают на страницу, принадлежащую FB, которая просто сообщает пользователю: "Теперь вы вошли в систему".

Шаги Repro:

  • Создайте UIWebView в приложении iOS и разместите модуль комментариев Facebook на странице, размещенной в каком-либо принадлежащем вам домене (например, http://foo.com/test.htm).
  • Нажмите кнопку "Вход" в модуле комментариев и обратите внимание, что вы перенаправляетесь на вход FB.
  • Войдите в систему с действительными учетными данными FB и наблюдайте, что происходит.

После входа в систему (шаг 3) я ожидаю, что после успешной проверки подлинности вы будете перенаправлены на исходную страницу (например, http://foo.com/test.htm), чтобы вы может продолжить ваше взаимодействие. Однако этого не происходит.

Вместо этого вы находитесь на странице, принадлежащей FB, которая просто говорит что-то вроде "Теперь вы вошли в систему", и вы попали туда. Не происходит перенаправления.

Действительно ли это ошибка или есть что-то еще, что я должен делать, чтобы обеспечить перенаправление?

4b9b3361

Ответ 1

Я видел, что что-то подобное происходит с входами FB других сайтов (например, Groupon), если вы загружаете их в UIWebView. Если это та же проблема (я думаю, что это так), это связано с тем, что Facebook открывает окно входа в всплывающее окно, как вы подозревали. Что происходит в обычном браузере, так это то, что для входа в систему открывается другое окно (всплывающее окно), а затем, когда пользователь входит в систему, это окно входа в систему возвращается в исходное окно, чтобы сказать, что оно вошло в систему. Вероятно, они используют EasyXDM или что-то похожее, Кажется, что существует несколько уровней стратегий для общения, включая Flash и postMessage.

В iOS (и Android) это должно означать, что он будет общаться с postMessage. Если вы отслеживаете URL-адреса, которые проходят через ваш UIWebView, вы должны увидеть что-то вроде этого ближе к концу:

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. Теперь у вас есть два окна для работы.

К сожалению, этого все еще недостаточно, так как при попытке запустить JavaScript на странице FB window.opener.postMessage или window.parent.postMessage он не работает, потому что window.parent и window.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;

Есть несколько способов вызывать Objective-C из JavaScript, включая этот из официальных документов. Вы можете ввести этот код в статическую страницу входа FB, о которой я упомянул, прежде чем использовать stringByEvaluatingJavaScriptFromString:. Я не мог найти подходящее время для этого, поэтому я просто добавляю его после загрузки страницы и вызываю doFragmentSend(), который является методом JavaScript FB на этой статической странице, которая обычно вызывается при загрузке тела.

Итак, теперь все, что нам нужно сделать, это передать эти данные в исходный UIWebView, вызвав postMessage. Это будет выглядеть примерно так:

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

Если вы еще не заметили, это огромный грязный хак, и я, вероятно, не рекомендую его, если у вас нет альтернативы, но это сработало для меня.

Ответ 2

Если вы просто поддерживаете 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
    }
}

Ответ 3

У меня была та же проблема. Я понял, что после входа в Facebook компоненты UIWebView пустые, в нем нет HTML-кода. Я решил проблему, проверив содержимое компонента UIWebView в функции webViewDidFinishLoad и перезагрузив его содержимое, когда обнаружил, что вход в систему Facebook вызывает белый (пустой экран):

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

Ответ 4

В настоящее время в мобильном браузере по умолчанию не поддерживается несколько окон. Альтернативное решение - отслеживать успешную переадресацию из facebook, например "close_popup.php? reload = https://" и перезагрузка страницы. Также убедитесь, что вы сохранили значение комментария facebook перед запросом на вход, чтобы его можно было снова добавить в поле комментариев.