Facebook Callback ajoute '# _ = _' à ​​l'URL de retour

479

Le rappel Facebook a commencé à s'ajouter #_=_ trait de soulignement de hachage à l'URL de retour

Quelqu'un sait-il pourquoi? Quelle est la solution?

zing ming
la source
35
Une idée de la façon dont Facebook ajoute ces personnages? Facebook redirige vers mon gestionnaire où je gère ensuite la redirection vers l'URL de retour, mais les caractères sont toujours ajoutés à l'URL.
Ben Foster
4
@BenFoster Je pense que vous trouverez si vous utilisez Fiddler ou similaire que lorsque FB redirige vers votre gestionnaire, le #_=_est en place, alors même si vous faites un Response.Redirectà l'endroit où vous voulez réellement le faire, le navigateur conserve le hachage , c'est pourquoi ce ne sont que les solutions de contournement côté client suggérées ci-dessous qui fonctionneront.
AakashM
17
2017, ce que le zuck
Ejonas GGgg
6
Mai 2017, toujours ....
Mirko
5
Mars 2018..yep toujours en cours
John Rogerson

Réponses:

239

via les mises à jour de la plateforme de Facebook :

Modification du comportement de redirection de session

Cette semaine, nous avons commencé à ajouter un fragment # ____ = ____ à redirect_uri lorsque ce champ est laissé vide. Veuillez vous assurer que votre application peut gérer ce comportement.

Pour éviter cela, définissez le redirect_uri dans votre demande d'URL de connexion comme suit: (en utilisant Facebook php-sdk)

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

MISE À JOUR

Ce qui précède est exactement comme indiqué dans la documentation pour résoudre ce problème. Cependant, la solution documentée de Facebook ne fonctionne pas. Veuillez envisager de laisser un commentaire sur le blog de Facebook Platform Updates et suivez ce bogue pour obtenir une meilleure réponse. D'ici là, ajoutez ce qui suit à votre balise head pour résoudre ce problème:

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

Ou une alternative plus détaillée (merci 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>
Ryan
la source
10
quel champ est laissé vide? C'est très cryptique
user210504
11
@Ryan Update fonctionne presque pour moi, je reçois toujours un hachage (/ #) à la fin. Pas content avec FB.
LenPopLilly
2
Je reçois toujours le / # également. quelqu'un met-il à jour ici? pour retirer le #
Tian Loon
6
Cette solution supprimera le hachage: <script type = "text / javascript"> var idx = window.location.toString (). IndexOf ("# _ = _"); if (idx> 0) {window.location = window.location.toString (). substring (0, idx); } </script> Assurez-vous simplement qu'il s'agit de la première balise de l'élément head.
Gorgi Rankovski
1
J'ai remarqué votre rapport de bogue ici: developers.facebook.com/bugs/1424488987806270 J'ai également essayé de chercher "fragment request_uri" avec les mêmes résultats.
Ryan
115

TL; DR

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

Version complète avec instructions étape par étape

// 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 = "";

    }

}

Pas à pas:

  1. Nous n'entrer dans le bloc de code si le fragmentest#_=_ .
  2. Vérifiez si le navigateur prend en charge HTML5 window.replaceState méthode .
    1. Nettoyez l'URL en vous séparant # et en ne prenant que la première partie.
    2. Dites historyde remplacer l'état actuel de la page par l'URL propre. Cela modifie l'entrée d'historique actuelle au lieu d'en créer une nouvelle. Cela signifie que les boutons Précédent et Suivant fonctionneront exactement comme vous le souhaitez. ;-)
  3. Si le navigateur ne prend pas en charge les impressionnantes méthodes d'historique HTML 5, nettoyez simplement l'URL du mieux que vous pouvez en définissant le hachage sur une chaîne vide. Il s'agit d'une solution de rechange médiocre car elle laisse toujours un hachage de fin (example.com/#) et ajoute également une entrée d'historique, de sorte que le bouton de retour vous ramènera à #_-_.

En savoir plus history.replaceState.

En savoir plus window.location.

Paul Schwarz
la source
2
A parfaitement fonctionné pour moi aussi. L'autre solution supprime tous les paramètres de requête.
AdeelMufti
Il fait la même chose pour google omniauth, donc j'obtiens une erreur sans correspondance d'itinéraire, il ajoute # (hashtag) après la demande uri https: //.....herokua‌ pp.com/auth/google_oa‌ uth2 / callback? state = 1‌ 9feaacfe23423jh5jhhGS‌ DFwb419049ebb18dabdf8‌ & code = 4 / glrY3-mSlTzwe‌ rwERTEG334eXcn3hOSxGu‌ c51BAlglPa4AU #
Shalafister's
Fonctionné pour moi mieux que la solution de @Ryan, car elle ne supprime pas la requête.
olivmir
Cette solution a mieux fonctionné que la solution de Ryan. Je passe certains paramètres à l'URL après qu'elle passe par l'authentification de Facebook et la solution de Ryan, pour une raison quelconque, supprime simplement tous les paramètres de l'URL. Cette solution fonctionne parfaitement dans mon cas.
BlueSun3k1
59

si vous souhaitez supprimer le "#" restant de l'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
  }
})
comme battements
la source
6
$ (window) .on ('load', function (e) {/ * likebeats's code * /} works.
ISHITOYA Kentaro
1
j'utilise ce code en changeant e.preventDefault (); à event.preventDefault ();
printf
Ce code suppose jQuery et un écouteur d'événement onWindowReady prenant l'argument e.
Jason Sperske
49

Cela a été mis en œuvre par Facebook par conception pour des raisons de sécurité. Voici l'explication d'Eric Osgood, un membre de l'équipe Facebook:

Cela a été marqué comme «par conception» car il empêche une vulnérabilité potentielle de sécurité.

Certains navigateurs ajoutent le fragment de hachage d'une URL à la fin d'une nouvelle URL vers laquelle ils ont été redirigés (si cette nouvelle URL n'a pas elle-même de fragment de hachage).

Par exemple, si example1.com renvoie une redirection vers example2.com, un navigateur allant vers example1.com # abc ira vers example2.com # abc, et le contenu du fragment de hachage de example1.com sera accessible à un script sur example2 .com.

Puisqu'il est possible d'avoir une redirection de flux d'authentification vers une autre, il serait possible d'avoir des données d'authentification sensibles d'une application accessibles à une autre.

Ceci est atténué en ajoutant un nouveau fragment de hachage à l'URL de redirection pour empêcher ce comportement de navigateur.

Si l'esthétique ou le comportement côté client de l'URL résultante est préoccupant, il serait possible d'utiliser window.location.hash (ou même une redirection côté serveur de votre choix) pour supprimer les caractères incriminés.

Source: https://developers.facebook.com/bugs/318390728250352/

Mark Murphy
la source
9
C'est la seule réponse qui explique réellement pourquoi cela se produit, merci, je pense que je vais laisser les caractères incriminés dans mes URL maintenant que je sais qu'ils ne sont pas un problème.
stephenmurdoch
1
Ceci est également mis en œuvre par Tumblr dans leurs redirections. (à partir du milieu de l'année 19) Merci d'avoir pointé l'explication du FB. Résolu facilement dans une application Passport simpliste en pointant simplement la redirection réussie vers "/ #" au lieu de simplement "/" (ce qui explique pourquoi je vois plus d'octothorps sur le Web, je pense ...)
RL Brown
10

Vous ne savez pas pourquoi ils le font, mais vous pouvez contourner ce problème en réinitialisant le hachage en haut de votre page:

if (window.location.hash == "#_=_")
  window.location.hash = "";
mixmasteralan
la source
9

Vous pouvez également spécifier votre propre hachage sur le redirect_uriparamètre du rappel Facebook, ce qui peut être utile dans certaines circonstances, par exemple /api/account/callback#home. Lorsque vous êtes redirigé, ce sera au moins un hachage qui correspond à un itinéraire connu si vous utilisez backbone.js ou similaire (vous n'êtes pas sûr de jquery mobile).

pkiddie
la source
8

Facebook utilise un cadre et à l'intérieur, tout fonctionne à l'aide de la communication AJAX. Le plus gros problème dans ce cas est la conservation de l'état actuel de la page. Si je comprends bien, Facebook a décidé d'utiliser des ancres simulées. Cela signifie que si vous avez cliqué quelque part, ils simulent cela comme une ancre à l'intérieur de votre page, et lorsque la communication AJAX démarre, ils modifient également le bit d'ancrage de votre URL.

Cette solution vous aide normalement lorsque vous essayez de recharger la page (pas ENTER, appuyez sur F5 ), car votre navigateur envoie l'URL complète avec des ancres au serveur Facebook. Par conséquent, Facebook récupère le dernier état (ce que vous voyez) et vous pouvez ensuite continuer à partir de là.

Lorsque le rappel revient avec, #_=_cela signifie que la page était dans son état de base avant de la quitter. Parce que cette ancre est analysée par le navigateur, vous ne devez pas vous en soucier.

Sándor Tóth
la source
2
Si vous avez un framework javascript comme backbone ou braise, c'est un problème car tout après le hachage est interprété par le routeur
Rudi
1
Les identifiants de fragments d'URL ("ancres") ne sont pas envoyés au navigateur sur demande. En outre, cette question concerne OAuth, pas le site de bureau principal. La raison en est la sécurité OAuth - empêchant les attaques dues à la création d'un URI de redirection malveillant.
AndrewF
8

Major ennuyeux, surtout pour les applications qui analysent l'URI et pas seulement lisent $ _GET ... Voici le hack que j'ai lancé ensemble ... Profitez-en!

<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>
Jeremy Whitt
la source
Soyez prudent lorsque vous analysez des données que vous ne créez pas. Les identificateurs de fragments d'URI ont été spécifiés dès RFC 1738 (en 1994), donc si vous utilisez un analyseur d'URI correct, cela ne devrait jamais être un problème.
AndrewF
6

Cela peut devenir une sorte de problème sérieux si vous utilisez un framework JS avec des URL hashbang (/ #! /), Par exemple Angular. En effet, Angular considérera les URL avec un fragment non-hashbang comme non valides et générera une erreur:

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

Si vous êtes dans un tel cas (et que vous redirigez vers la racine de votre domaine), au lieu de faire:

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

Faites simplement:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest
neemzy
la source
1.2+, cela fonctionne très bien. Pour la version 1.0 et inférieure, utilisez window.location.hash = '';
Pradeep Mahdevu
1
Oui, je n'ai testé cela que sur 1.2, merci pour la spécification!
neemzy
Et puis il y a le mode html5
rocketspacer
5

Je ne vois pas comment ce problème est lié à Facebook AJAX. En fait, le problème se produit également avec JavaScript désactivé et les connexions basées uniquement sur la redirection.

Un exemple d'échange avec facebook:

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#_  

Cela n'arrive qu'avec Firefox pour moi aussi.

Sebastian Tusk
la source
4

L'ajout de cela à ma page de redirection a résolu le problème pour moi ...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}
neokio
la source
1
cela provoque un changement d'emplacement de la fenêtre, initiant une actualisation de la page
rpearce
3

Avec le routeur ui angulaire et angulaire, vous pouvez résoudre ce problème

    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
la source
ne fonctionne pas ici - l'itinéraire change avant l'application de la règle ()
Maël Nison
3

Si vous utilisez vue-router, vous pouvez ajouter à la liste des itinéraires:

{
  path: '/_=_',
  redirect: '/', // <-- or other default route
},
Slawomir
la source
2

Un changement a été introduit récemment dans la façon dont Facebook gère les redirections de session. Voir "Changement de comportement de redirection de session" dans le billet de blog Operation Developer Love de cette semaine pour l'annonce.

Dhiren Patel
la source
1
Je ne suis pas sûr, de quoi parle-t-il ici
user210504
2

Pour moi, je fais la redirection JavaScript vers une autre page pour m'en débarrasser #_=_. Les idées ci-dessous devraient fonctionner. :)

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}
Eng Cy
la source
ce n'est pas une bonne idée, je pense parce que vous créez plusieurs demandes inutiles
Jacek Pietal
1

Une solution de contournement qui a fonctionné pour moi (en utilisant Backbone.js), a été d'ajouter "# /" à la fin de l'URL de redirection transmise à Facebook. Facebook conservera le fragment fourni et n'ajoutera pas son propre "_ = _".

Au retour, Backbone supprimera la partie "# /". Pour AngularJS, en ajoutant "#!" à l'URL de retour devrait fonctionner.

Notez que l'identifiant de fragment de l'URL d'origine est conservé lors de la redirection (via les codes d'état HTTP 300, 301, 302 et 303) par la plupart des navigateurs, sauf si l'URL de redirection possède également un identifiant de fragment. Cela semble être un comportement recommandé .

Si vous utilisez un script de gestionnaire qui redirige l'utilisateur ailleurs, vous pouvez ajouter "#" à l'URL de redirection ici pour remplacer l'identificateur de fragment par une chaîne vide.

Ivo Smits
la source
1

Je sais que cette réponse est en retard, mais si vous utilisez passportjs, vous voudrez peut-être le voir.

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

J'ai écrit ce middleware et l'ai appliqué à une instance de serveur express, et l'URL d'origine que j'ai est sans le "#_=_". Il ressemble à cela lorsque nous appliquons l'instance de passporJS en tant que middleware à l'instance de serveur, il ne prend pas ces caractères, mais n'est visible que dans la barre d'adresse de nos navigateurs.

Krishna
la source
3
"# _ = _" disponible uniquement sur le client. Critique: en.wikipedia.org/wiki/Fragment_identifier
alditis
1

J'utilise celui-ci, pour supprimer également le symbole '#'.

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        window.location.href = window.location.href.split('#_=_')[0];
    }
</script>
Simon
la source
0

En utilisant Angular 2 (RC5) et des routes basées sur le hachage, je fais ceci:

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

et

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

Pour autant que je comprends, le =caractère de l'itinéraire est interprété comme faisant partie de la définition facultative des paramètres de l'itinéraire (voir https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters ) , donc pas impliqué dans la correspondance d'itinéraire.

rcomblen
la source
0

Pour les utilisateurs de PHP SDK

J'ai résolu le problème simplement en retirant la pièce supplémentaire avant de la transférer.

 $loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);
 $loginURL = str_replace("#_=_", "", $loginURL);
 header("Location: " . $loginURL);
Nanoripper
la source
0

Cela supprimerait les caractères ajoutés à votre URL

<script type="text/javascript">
 var idx=window.location.toString().indexOf("#_=_"); 
   if (idx > 0) { 
     window.location = window.location.toString().substring(0, idx); 
   } 
</script>
Rotimi
la source
0

La solution la plus simple et la plus propre pour supprimer "# _ = _" (PHP):

Au lieu de "header (" Location: xxx.php ");" pour utiliser "echo (" location.href = 'xxx.php'; ");"

user3806621
la source