Обратный звонок Facebook добавляет '# _ = _' к URL возврата

479

Обратный вызов Facebook начал добавлять #_=_подчеркивание хеша в URL возврата

Кто-нибудь знает почему? Каково решение?

Zing Ming
источник
35
Есть идеи, как фейсбук добавляет этих персонажей? Facebook перенаправляет на мой обработчик, где я затем обрабатываю перенаправление на обратный URL, но символы все еще добавляются к URL.
Бен Фостер
4
@BenFoster Я думаю, вы обнаружите, используете ли вы Fiddler или подобное, что когда FB перенаправляет на ваш обработчик, #_=_он на месте, тогда, даже если вы делаете то, Response.Redirectчто вам действительно нужно, браузер поддерживает хэш , поэтому это только обходные пути на стороне клиента, предложенные ниже, которые будут работать.
AakashM
17
2017, какой цук
Эхонас ГГгг
6
Май 2017, еще ....
Мирко
5
Март 2018 года. Да, все еще происходит
Джон Роджерсон

Ответы:

239

через обновления платформы Facebook :

Изменение в поведении перенаправления сеанса

На этой неделе мы начали добавлять фрагмент # ____ = ____ к redirect_uri, когда это поле оставлено пустым. Пожалуйста, убедитесь, что ваше приложение может справиться с этим поведением.

Чтобы предотвратить это, установите redirect_uri в вашем URL-адресе для входа в систему следующим образом: (используя Facebook php-sdk)

$facebook->getLoginUrl(array('redirect_uri' => $_SERVER['SCRIPT_URI'],'scope' => 'user_about_me'));

ОБНОВИТЬ

Вышесказанное в точности соответствует документации, чтобы исправить это. Однако документированное решение Facebook не работает. Пожалуйста, оставьте комментарий в сообщении блога Facebook Platform Updates и следуйте этой ошибке, чтобы получить лучший ответ. А до тех пор добавьте следующее в тег head для решения этой проблемы:

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        window.location.hash = '';
    }
</script>

Или более подробная альтернатива (спасибо niftylettuce ):

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        if (window.history && history.pushState) {
            window.history.pushState("", document.title, window.location.pathname);
        } else {
            // Prevent scrolling by storing the page's current scroll offset
            var scroll = {
                top: document.body.scrollTop,
                left: document.body.scrollLeft
            };
            window.location.hash = '';
            // Restore the scroll offset, should be flicker free
            document.body.scrollTop = scroll.top;
            document.body.scrollLeft = scroll.left;
        }
    }
</script>
Райан
источник
10
какое поле оставлено пустым? Это очень загадочно
user210504
11
Обновление @Ryan почти работает для меня, я все еще получаю хеш (/ #) в конце. Не доволен FB.
ЛенПопЛилли
2
Я все еще получаю / # также. кто-нибудь обновлять здесь? чтобы убрать #
Тянь Лун
6
Это решение удалит хеш: <script type = "text / javascript"> var idx = window.location.toString (). IndexOf ("# _ = _"); if (idx> 0) {window.location = window.location.toString (). substring (0, idx); } </ script> Просто убедитесь, что это первый тег в элементе head.
Горги Ранковски
1
Я заметил ваш отчет об ошибке здесь: developers.facebook.com/bugs/1424488987806270 Я также попробовал свои силы в поиске «фрагмента request_uri» с теми же результатами.
Райан
115

TL; DR

if (window.location.hash === "#_=_"){
    history.replaceState 
        ? history.replaceState(null, null, window.location.href.split("#")[0])
        : window.location.hash = "";
}

Полная версия с пошаговыми инструкциями

// Test for the ugliness.
if (window.location.hash === "#_=_"){

    // Check if the browser supports history.replaceState.
    if (history.replaceState) {

        // Keep the exact URL up to the hash.
        var cleanHref = window.location.href.split("#")[0];

        // Replace the URL in the address bar without messing with the back button.
        history.replaceState(null, null, cleanHref);

    } else {

        // Well, you're on an old browser, we can get rid of the _=_ but not the #.
        window.location.hash = "";

    }

}

Шаг за шагом:

  1. Мы попадем в блок кода, только если fragment есть #_=_.
  2. Проверьте, поддерживает ли браузер window.replaceStateметод HTML5 .
    1. Очистите URL, разделив на # и взяв только первую часть.
    2. Скажите, historyчтобы заменить текущее состояние страницы чистым URL. Это изменяет текущую запись истории вместо создания новой. Это означает, что кнопки «назад» и «вперед» будут работать так, как вы хотите. ;-)
  3. Если браузер не поддерживает удивительные методы истории HTML 5, просто очистите URL как можно лучше, установив в хеш пустую строку. Это плохой запасной вариант, поскольку он по-прежнему оставляет конечный хеш (example.com/#), а также добавляет запись в историю, поэтому кнопка возврата вернет вас назад #_-_.

Узнать больше о history.replaceState.

Узнайте больше о window.location.

Пол Шварц
источник
2
Сработало идеально для меня тоже. Другое решение избавляет от любых параметров запроса.
AdeelMufti
Он делает то же самое для google omniauth, поэтому я получаю сообщение об ошибке без совпадения маршрута, он добавляет # (хэштег) после запроса uri https: //.....herokua‌ pp.com/auth/google_oa‌ uth2 / callback? state = 1‌ 9feaacfe23423jh5jhhGS‌ DFwb419049ebb18dabdf8‌ & code = 4 / glrY3-mSlTzwe‌ rwERTEG334eXcn3hOSxGu‌ c51BAlglPa4AU #
Шалафистер
У меня получилось лучше, чем решение @Ryan, так как оно не удаляет запрос.
Оливмир
Это решение работало лучше, чем решение Райана. Я передаю некоторые параметры URL-адресу после того, как он проходит проверку подлинности Facebook и решение Райана, по какой-то причине просто удаляет каждый параметр из URL-адреса. Это решение отлично работает в моем случае.
BlueSun3k1
59

если вы хотите удалить оставшиеся "#" из URL

$(window).on('load', function(e){
  if (window.location.hash == '#_=_') {
    window.location.hash = ''; // for older browsers, leaves a # behind
    history.pushState('', document.title, window.location.pathname); // nice and clean
    e.preventDefault(); // no page reload
  }
})
likebeats
источник
6
$ (window) .on ('load', function (e) {/ * likebeats код * /} работает.
ИШИТОЯ Кентаро
1
я использую этот код путем изменения e.preventDefault (); к event.preventDefault ();
printf
Этот код принимает jQuery, а слушатель события onWindowReady принимает аргумент e.
Джейсон Сперске
49

Это было реализовано Facebook специально для обеспечения безопасности. Вот объяснение от Эрика Осгуда, члена команды Facebook:

Это было помечено как «намеренно», поскольку предотвращает потенциальную уязвимость безопасности.

Некоторые браузеры добавляют фрагмент хеша из URL-адреса в конец нового URL-адреса, на который они были перенаправлены (если этот новый URL-адрес сам по себе не имеет хеш-фрагмента).

Например, если example1.com возвращает перенаправление на example2.com, то браузер, идущий на example1.com # abc, перейдет на example2.com # abc, и содержимое фрагмента хеша из example1.com будет доступно сценарию на example2 .com.

Поскольку возможно перенаправление одного потока аутентификации в другой, можно было бы получить конфиденциальные данные аутентификации из одного приложения, доступные для другого.

Это можно уменьшить, добавив новый хеш-фрагмент к URL-адресу перенаправления, чтобы предотвратить такое поведение браузера.

Если эстетика или поведение на стороне клиента результирующего URL-адреса вызывает озабоченность, можно было бы использовать window.location.hash (или даже собственное перенаправление на стороне сервера) для удаления оскорбительных символов.

Источник: https://developers.facebook.com/bugs/318390728250352/

Марк Мерфи
источник
9
Это единственный ответ, который на самом деле объясняет, почему это происходит, спасибо, я думаю, я оставлю оскорбительные символы в своих URL-адресах, теперь, когда я знаю, что они не проблема.
stephenmurdoch
1
Это также реализовано Tumblr в их перенаправлениях. (по состоянию на середину 19 года) Спасибо за указание на объяснение FB. Легко решается в упрощенном приложении Passport, просто указывая успешное перенаправление на «/ #» вместо простого «/» (я думаю, что в Интернете объясняется, почему я вижу больше запаздывающих
Р.Л. Браун
10

Не уверен, почему они это делают, но вы можете обойти это, сбросив хеш в верхней части своей страницы:

if (window.location.hash == "#_=_")
  window.location.hash = "";
mixmasteralan
источник
9

Вы также можете указать свой собственный хэш в redirect_uriпараметре для обратного вызова Facebook, который может быть полезен при определенных обстоятельствах, например /api/account/callback#home. Когда вы будете перенаправлены назад, это будет, по крайней мере, хеш, который соответствует известному маршруту, если вы используете backbone.js или подобное (не уверен насчет jquery mobile).

pkiddie
источник
8

Facebook использует фрейм, и внутри него все работает, используя AJAX-связь. Самая большая проблема в этом случае - сохранение текущего состояния страницы. Насколько я понимаю, Facebook решил использовать смоделированные анкеры. Это означает, что если вы щелкнули где-то, они имитируют это как привязку внутри вашей страницы, а когда начинается связь AJAX, они также меняют бит привязки вашего URL.

Это решение обычно помогает вам при перезагрузке страницы (не ENTER, нажмите F5 ), потому что ваш браузер отправляет весь URL с привязками на сервер Facebook. Таким образом, Facebook выбирает последнее состояние (то, что вы видите), и вы можете продолжить оттуда.

Когда обратный вызов возвращается вместе с #_=_ним, это означает, что страница была в своем базовом состоянии перед тем, как покинуть ее. Поскольку эта привязка анализируется браузером, вам не нужно беспокоиться об этом.

Шандор Тот
источник
2
Если у вас есть javascript-фреймворк, такой как backbone или ember, это проблема, так как все после хэша интерпретируется маршрутизатором
Rudi
1
Идентификаторы фрагмента URL («якоря») не отправляются в браузер по запросу. Кроме того, этот вопрос касается OAuth, а не основного рабочего стола сайта. Причиной этого является безопасность OAuth - предотвращение атак из-за создания вредоносного URI перенаправления.
AndrewF
8

Главное раздражает, особенно для приложений, которые анализируют URI, а не просто читают $ _GET ... Вот хак, который я бросил вместе ... Наслаждайтесь!

<html xmlns:fb='http://www.facebook.com/2008/fbml'>
<head>
        <script type="text/javascript">
        // Get rid of the Facebook residue hash in the URI
        // Must be done in JS cuz hash only exists client-side
        // IE and Chrome version of the hack
        if (String(window.location.hash).substring(0,1) == "#") {
                window.location.hash = "";
                window.location.href=window.location.href.slice(0, -1);
                }
        // Firefox version of the hack
        if (String(location.hash).substring(0,1) == "#") {
                location.hash = "";
                location.href=location.href.substring(0,location.href.length-3);
                }
        </script>
</head>
<body>
URI should be clean
</body>
</html>
Джереми Уитт
источник
Будьте осторожны, делая предположения при разборе любых данных, которые вы не создаете. Идентификаторы фрагментов URI были определены еще в RFC 1738 (в 1994 году), поэтому, если вы используете правильный анализатор URI, это никогда не должно быть проблемой.
AndrewF
6

Это может стать серьезной проблемой, если вы используете инфраструктуру JS с URL-адресами hashbang (/ #! /), Например, Angular. Действительно, Angular будет считать недействительными URL-адреса с фрагментом без хэш-банга и выдаст ошибку:

Error: Invalid url "http://example.com/#_=_", missing hash prefix "#!".

Если вы находитесь в таком случае (и перенаправляете в корневой каталог своего домена), вместо того, чтобы делать:

window.location.hash = ''; // goes to /#, which is no better

Просто сделайте:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest
neemzy
источник
1.2+, это работает потрясающе. Для версии 1.0 и ниже используйте window.location.hash = '';
Прадип Махдеву
1
Да, я проверял это только на 1.2, спасибо за спецификацию!
neemzy
И тогда есть режим html5
rocketspacer
5

Я не вижу, как эта проблема связана с Facebook AJAX. На самом деле проблема также возникает с отключенным JavaScript и чисто перенаправленным входом в систему.

Пример обмена с фейсбуком:

1. GET <https://www.facebook.com/dialog/oauth?client_id=MY_APP_ID&scope=email&redirect_uri=MY_REDIRECT_URL> RESPONSE 302 Found Location: <https://www.facebook.com/connect/uiserver.php?[...]>  
2. GET <https://www.facebook.com/connect/uiserver.php?[...]> RESPONSE 302 Found MY_REDIRECT_URL?code=FB_CODE#_  
3. GET MY_REDIRECT_URL?code=FB_CODE#_  

Случается только с Firefox для меня тоже.

Себастьян Туск
источник
4

Добавление этого на мою страницу перенаправления решило проблему для меня ...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}
neokio
источник
1
это вызывает изменение расположения окна, инициируя обновление страницы
rpearce
3

С угловым и угловым интерфейсом UI, вы можете это исправить

    app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {

      // Make a trailing slash optional for all routes
      // - Note: You'll need to specify all urls with a trailing slash if you use this method.
      $urlRouterProvider.rule(function ($injector, $location) {
        /***
        Angular misbehaves when the URL contains a "#_=_" hash.

        From Facebook:
          Change in Session Redirect Behavior
          This week, we started adding a fragment #_=_ to the redirect_uri when this field is left blank.
          Please ensure that your app can handle this behavior.

        Fix:
          http://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url#answer-7297873
        ***/
        if ($location.hash() === '_=_'){
          $location.hash(null);
        }

        var path = $location.url();

        // check to see if the path already has a slash where it should be
        if (path[path.length - 1] === '/' || path.indexOf('/?') > -1) {
          return;
        }
        else if (path.indexOf('?') > -1) {
          $location.replace().path(path.replace('?', '/?'));
        }
        else {
          $location.replace().path(path + '/');
        }
      });

      // etc ...
    });
});
rebelliard
источник
здесь не работает - маршрут изменяется до применения правила ()
Maël Nison
3

Если вы используете vue-router, вы можете добавить в список маршрутов:

{
  path: '/_=_',
  redirect: '/', // <-- or other default route
},
Славомир
источник
2

Недавно было внесено изменение в то, как Facebook обрабатывает перенаправления сеансов. См. «Изменение в поведении перенаправления сеанса» в сообщении на этой неделе в блоге « Operation Developer Love» .

Дирен Патель
источник
1
Я не уверен, что он имеет в виду здесь
user210504
2

Для меня я делаю перенаправление JavaScript на другую страницу, чтобы избавиться от #_=_. Идеи ниже должны работать. :)

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}
Eng Cy
источник
Я думаю, это не очень хорошая идея, потому что вы создаете несколько бесполезных запросов
Яцек Пьетал
1

Обходной путь, который работал для меня (используя Backbone.js), заключался в добавлении «# /» в конец URL-адреса перенаправления, переданного в Facebook. Facebook сохранит предоставленный фрагмент и не добавит свой собственный "_ = _".

По возвращении Backbone удалит часть «# /». Для AngularJS добавление "#!" на обратный URL должен работать.

Обратите внимание, что идентификатор фрагмента исходного URL-адреса сохраняется при перенаправлении (через коды состояния HTTP 300, 301, 302 и 303) большинством браузеров, если URL-адрес перенаправления также не имеет идентификатора фрагмента. Это, кажется, рекомендуемое поведение .

Если вы используете скрипт-обработчик, который перенаправляет пользователя в другое место, вы можете добавить «#» к URL-адресу перенаправления, чтобы заменить идентификатор фрагмента пустой строкой.

Иво Смитс
источник
1

Я знаю, что этот ответ опоздал, но если вы используете passportjs, возможно, вы захотите это увидеть.

return (req, res, next) => {
    console.log(req.originalUrl);
    next();
};

Я написал это промежуточное программное обеспечение и применил его к экземпляру Express Server, а исходный URL-адрес у меня без "#_=_". Похоже, когда мы применяем экземпляр passporJS в качестве промежуточного программного обеспечения к экземпляру сервера, он не принимает эти символы, а виден только в адресной строке наших браузеров.

Кришна
источник
3
«# _ = _» доступно только на клиенте. Обзор: en.wikipedia.org/wiki/Fragment_identifier
alditis
1

Я использую этот, чтобы удалить символ «#».

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        window.location.href = window.location.href.split('#_=_')[0];
    }
</script>
Саймон
источник
0

Используя Angular 2 (RC5) и основанные на хэше маршруты, я делаю это:

const appRoutes: Routes = [
  ...
  {path: '_', redirectTo: '/facebookLoginSuccess'},
  ...
]

а также

export const routing = RouterModule.forRoot(appRoutes, { useHash: true });

Насколько я понимаю, =символ в маршруте интерпретируется как часть необязательного определения параметров маршрута (см. Https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters ) , поэтому не участвует в сопоставлении маршрута.

rcomblen
источник
0

Для пользователей PHP SDK

Я исправил проблему, просто удалив лишнюю часть перед пересылкой.

 $loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);
 $loginURL = str_replace("#_=_", "", $loginURL);
 header("Location: " . $loginURL);
Nanoripper
источник
0

Это удалит добавленные символы в ваш URL

<script type="text/javascript">
 var idx=window.location.toString().indexOf("#_=_"); 
   if (idx > 0) { 
     window.location = window.location.toString().substring(0, idx); 
   } 
</script>
Rotimi
источник
0

Самое простое и чистое решение для удаления "# _ = _" (PHP):

Вместо "header (" Location: xxx.php ");" использовать "echo (" location.href = 'xxx.php'; ");"

user3806621
источник