web-dev-qa-db-fra.com

Facebook Callback ajoute '# _ = _' pour renvoyer l'URL

Le rappel Facebook a commencé à ajouter le caractère de soulignement #_=_ dièse à l'URL de retour

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

442
zing ming

via mises à jour de la plateforme de Facebook :

Changer le comportement de redirection de session

Cette semaine, nous avons commencé à ajouter un fragment # ____ = ____ à la redirect_uri quand ce champ est laissé vide. Assurez-vous que votre application peut gérer cela comportement.

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

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

METTRE À JOUR

Ce qui précède correspond exactement à la documentation pour résoudre ce problème. Cependant, la solution documentée de Facebook ne fonctionne pas. Pensez à laisser un commentaire sur le publication sur le blog de la plate-forme Facebook et suivez ce bug pour obtenir une meilleure réponse. Jusque-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>
229
Ryan

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 pas à pas

// 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 entrerons dans le bloc de code uniquement si la variable fragment est #_=_.
  2. Vérifiez si le navigateur prend en charge la méthode HTML5 window.replaceState .
    1. Nettoyez l'URL en découpant sur # et en ne prenant que la première partie.
    2. Indiquez à history de remplacer l'état de la page en cours par l'URL vierge. 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 méthodes d'historique impressionnantes HTML 5, nettoyez simplement l'URL du mieux que vous pouvez en définissant le hachage sur une chaîne vide. Cette solution de repli est médiocre car elle laisse toujours un hachage de fin (exemple.com/#) et ajoute également une entrée d'historique. Le bouton Précédent vous ramène à #_-_

En savoir plus sur history.replaceState .

En savoir plus sur window.location .

99
PapaSierra

si vous voulez 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
  }
})
57
likebeats

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

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

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

Par exemple, si exemple1.com renvoie une redirection vers exemple2.com, un fichier navigateur allant à example1.com # abc ira à example2.com # abc, et au Le contenu du fragment de hachage de example1.com serait accessible à un script sur example2.com.

Puisqu'il est possible d'avoir un flux d'autorisations redirigé vers un autre, c'est serait possible d'avoir des données d'authentification sensibles d'une application accessible à un autre.

Ceci est atténué par l'ajout d'un nouveau fragment de hachage à l'URL de redirection pour empêcher ce comportement du navigateur.

Si l'esthétique ou le comportement côté client de l'URL résultante sont Si vous vous inquiétez, il serait possible d’utiliser window.location.hash (ou même une redirection côté serveur) pour supprimer le. off. personnages.

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

33
Mark Murphy

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

if (window.location.hash == "#_=_")
  window.location.hash = "";
10
mixmasteralan

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

9
pkiddie

Major ennuyeux, surtout pour les applications qui analysent l'URI et pas seulement lire le $ _GET ... Voici le hack que j'ai jeté ensemble ... Enjoy!

<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>
8
Jeremy Whitt

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 de préserver l’état actuel de la page. Si j'ai bien compris, 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 commence, 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 entière avec les 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 retourne 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 n'avez pas à vous en préoccuper.

8
Sándor Tóth

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

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

Si vous êtes dans un tel cas (et que vous le 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
6
neemzy

Je ne vois pas en quoi ce problème est lié à Facebook AJAX. En fait, le problème se produit également avec JavaScript désactivé et les connexions à base purement redirigée. 

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

Ne se produit qu'avec Firefox pour moi aussi.

5
Sebastian Tusk

Ajouter ceci à ma page de redirection corrigeait le problème pour moi ...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}
4
neokio

Avec un 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 ...
    });
});
3
rebelliard

Si vous utilisez vue-router, vous pouvez ajouter à la liste des routes:

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

Une modification a récemment été apportée à la manière dont Facebook gère les redirections de session. Voir "Modification du comportement de redirection de session" dans Operation Developer Love billet de blog pour l'annonce.

2
Dhiren Patel

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

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}
2
Eng Cy

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

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

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

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

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

1
Krishna

Une solution qui fonctionnait pour moi (à l’aide de Backbone.js) consistait à ajouter "# /" à la fin de l’URL de redirection transmise à Facebook. Facebook conservera le fragment fourni et ne pas ajouter son propre "_ = _".

À son retour, Backbone supprimera la partie "# /". Pour AngularJS, ajouter "#!" à 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. Ceci semble être le 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.

1
Ivo Smits

Pour PHP Utilisateurs du SDK

J'ai résolu le problème simplement en supprimant la partie supplémentaire avant le transfert.

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

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

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

et

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

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

0
rcomblen

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>
0
Akintunde-Rotimi