Callback di Facebook aggiunge '# _ = _' all'URL di ritorno


479

La richiamata di Facebook ha iniziato ad aggiungere la #_=_sottolineatura dell'hash all'URL di ritorno

Qualcuno sa perché? Qual'è la soluzione?


35
Qualche idea su come Facebook aggiunge questi personaggi? Facebook reindirizza al mio gestore dove quindi gestisco il reindirizzamento all'URL di ritorno, ma i caratteri vengono comunque aggiunti all'URL.
Ben Foster,

4
@BenFoster Penso che scoprirai se usi Fiddler o simili che quando FB reindirizza al tuo gestore, #_=_è a posto, quindi anche se fai un punto Response.Redirectdove vuoi davvero fare, il browser mantiene l'hash , motivo per cui sono solo le soluzioni alternative sul lato client suggerite di seguito che funzioneranno.
AakashM,

17
2017, what the zuck
Ejonas GGgg

6
Maggio 2017, ancora ....
Mirko

5
Marzo 2018 ... ancora in corso
John Rogerson,

Risposte:


239

tramite gli aggiornamenti della piattaforma di Facebook :

Modifica del comportamento di reindirizzamento della sessione

Questa settimana, abbiamo iniziato ad aggiungere un frammento # ____ = ____ a redirect_uri quando questo campo viene lasciato vuoto. Assicurati che la tua app sia in grado di gestire questo comportamento.

Per evitare ciò, impostare redirect_uri nella richiesta dell'URL di accesso in questo modo: (usando Facebook php-sdk)

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

AGGIORNARE

Quanto sopra è esattamente come dice la documentazione per risolvere questo problema. Tuttavia, la soluzione documentata di Facebook non funziona. Ti consigliamo di lasciare un commento sul post sul blog degli aggiornamenti della piattaforma di Facebook e seguire questo errore per ottenere una risposta migliore. Fino ad allora, aggiungi quanto segue al tag head per risolvere questo problema:

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

O un'alternativa più dettagliata (grazie 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
quale campo viene lasciato vuoto? Questo è molto enigmatico
user210504

11
@Ryan Update funziona quasi per me, ho ancora un hash (/ #) alla fine. Non contento di FB.
LenPopLilly,

2
Ottengo anche il / #. qualcuno aggiorna qui? per rimuovere il #
Tian Loon

6
Questa soluzione cancellerà l'hash: <script type = "text / javascript"> var idx = window.location.toString (). IndexOf ("# _ = _"); if (idx> 0) {window.location = window.location.toString (). substring (0, idx); } </script> Assicurati solo che sia il primo tag nell'elemento head.
Gorgi Rankovski,

1
Ho notato la tua segnalazione di bug qui: developers.facebook.com/bugs/1424488987806270 Ho anche provato a cercare "frammento request_uri" con gli stessi risultati.
Ryan,

115

TL; DR

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

Versione completa con istruzioni dettagliate

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

    }

}

Passo dopo passo:

  1. Entreremo nel blocco di codice solo se lo fragmentè #_=_.
  2. Controlla se il browser supporta il window.replaceStatemetodo HTML5 .
    1. Pulisci l'URL suddividendolo #e prendendo solo la prima parte.
    2. Indica historydi sostituire lo stato della pagina corrente con l'URL pulito. Ciò modifica la voce della cronologia corrente invece di crearne una nuova. Ciò significa che i pulsanti avanti e indietro funzioneranno nel modo desiderato. ;-)
  3. Se il browser non supporta i fantastici metodi di cronologia HTML 5, ripulisci l'URL nel miglior modo possibile impostando l'hash su stringa vuota. Questo è un fallback scadente perché lascia ancora un hash finale (esempio.com/#) e inoltre aggiunge una voce di cronologia, quindi il pulsante Indietro ti riporterà a #_-_.

Ulteriori informazioni su history.replaceState.

Ulteriori informazioni su window.location.


2
Ha funzionato perfettamente anche per me. L'altra soluzione elimina qualsiasi parametro di query.
AdeelMufti,

Fa la stessa cosa per google omniauth, quindi ricevo un errore che non corrisponde a un percorso, aggiunge # (hashtag) dopo la richiesta uri https: //.....herokua‌ pp.com/auth/google_oa‌ uth2 / callback? state = 1‌ 9feaacfe23423jh5jhhGS‌ DFwb419049ebb18dabdf8‌ & code = 4 / glrY3-mSlTzwe‌ rwERTEG334eXcn3hOSxGu‌ c51BAlglPa4AU #
di Shalafister

Ha funzionato per me meglio della soluzione di @Ryan, in quanto non elimina la query.
olivmir,

Questa soluzione ha funzionato meglio della soluzione di Ryan. Passo alcuni parametri all'URL dopo che passa attraverso l'autenticazione di Facebook e la soluzione di Ryan, per qualche ragione rimuove tutti i parametri dall'URL. Questa soluzione funziona perfettamente nel mio caso.
BlueSun3k1

59

se desideri rimuovere il "#" rimanente dall'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
  }
})

6
$ (window) .on ('load', function (e) {/ * likebeats's code * /} funziona.
ISHITOYA Kentaro

1
io uso questo codice cambiando e.preventDefault (); a event.preventDefault ();
printf

Questo codice presuppone jQuery e un listener di eventi onWindowReady che accetta l'argomento e.
Jason Sperske,

49

Questo è stato implementato da Facebook per motivi di sicurezza. Ecco la spiegazione di Eric Osgood, un membro del team di Facebook:

Questo è stato contrassegnato come "progettato" perché impedisce una potenziale vulnerabilità della sicurezza.

Alcuni browser aggiungeranno il frammento di hash da un URL alla fine di un nuovo URL a cui sono stati reindirizzati (se quel nuovo URL non ha esso stesso un frammento di hash).

Ad esempio, se example1.com restituisce un reindirizzamento a example2.com, un browser andando a example1.com # abc andrà a example2.com # abc e il contenuto del frammento di hash da example1.com sarebbe accessibile a uno script su example2 .com.

Dal momento che è possibile avere un flusso di reindirizzamento di un flusso verso un altro, sarebbe possibile avere dati di autenticazione sensibili da un'app accessibile a un'altra.

Ciò viene mitigato aggiungendo un nuovo frammento di hash all'URL di reindirizzamento per impedire questo comportamento del browser.

Se l'estetica o il comportamento sul lato client dell'URL risultante sono preoccupanti, sarebbe possibile utilizzare window.location.hash (o anche un reindirizzamento sul lato server) per rimuovere i caratteri offensivi.

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


9
Questa è l'unica risposta che in realtà spiega perché questo accada, grazie, penso che lascerò i caratteri offensivi nei miei URL ora che so che non sono un problema.
Stephenmurdoch

1
Questo è anche implementato da Tumblr nei loro reindirizzamenti. (a partire dalla metà del '19) Grazie per aver indicato la spiegazione di FB. Facilmente risolto in un'app Passport semplicistica semplicemente indicando il reindirizzamento riuscito a "/ #" anziché solo "/" (il che spiega perché vedo più ottagotipi finali sul web, penso ...)
RL Brown

10

Non sei sicuro del perché lo stiano facendo, ma potresti aggirare il problema reimpostando l'hash nella parte superiore della pagina:

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

9

Puoi anche specificare il tuo hash sul redirect_uriparametro per il callback di Facebook, che potrebbe essere utile in determinate circostanze, ad es /api/account/callback#home. Quando verrai reindirizzato indietro, sarà almeno un hash che corrisponde a una route nota se stai usando backbone.js o simili (non sei sicuro di jquery mobile).


8

Facebook utilizza una cornice e al suo interno tutto funziona utilizzando la comunicazione AJAX. Il problema più grande in questo caso è preservare lo stato della pagina corrente. A quanto ho capito, Facebook ha deciso di utilizzare ancore simulate. Ciò significa che se hai fatto clic da qualche parte, lo simulano come un'ancora all'interno della tua pagina e quando inizia la comunicazione AJAX, cambiano anche il bit di ancoraggio del tuo URL.

Questa soluzione ti aiuta normalmente quando tenti di ricaricare la pagina (non INVIO, premi F5), perché il tuo browser invia l'intero URL con ancore al server di Facebook. Pertanto Facebook rileva l'ultimo stato (quello che vedi) e sei quindi in grado di continuare da lì.

Quando il callback ritorna con #_=_esso significa che la pagina era nel suo stato di base prima di lasciarla. Poiché questo ancoraggio viene analizzato dal browser, non è necessario preoccuparsene.


2
Se hai un framework javascript come backbone o ember è un problema dato che tutto ciò che segue l'hash viene interpretato dal router
Rudi

1
Gli identificatori di frammenti URL ("ancore") non vengono inviati al browser su una richiesta. Inoltre, questa domanda riguarda OAuth, non il sito desktop principale. Il motivo di ciò è la sicurezza di OAuth , che impedisce gli attacchi dovuti alla creazione di un URI di reindirizzamento dannoso.
AndrewF,

8

Importante fastidioso, specialmente per le app che analizzano l'URI e non solo leggono $ _GET ... Ecco l'hack che ho messo insieme ... Divertiti!

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

Fai attenzione a fare ipotesi quando analizzi i dati che non crei. Gli identificatori di frammenti URI sono stati specificati già a partire da RFC 1738 (nel 1994), quindi se si utilizza un parser URI corretto, questo non dovrebbe mai essere un problema.
AndrewF,

6

Questo può diventare una specie di problema serio se stai usando un framework JS con URL hashbang (/ #! /), Ad esempio Angular. Infatti, Angular considererà gli URL con un frammento non hashbang come non validi e genererà un errore:

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

Se ti trovi in ​​questo caso (e stai reindirizzando alla radice del tuo dominio), invece di fare:

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

Fai semplicemente:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest

1.2+, funziona alla grande. Per 1.0 e precedenti usa window.location.hash = '';
Pradeep Mahdevu il

1
Sì, l'ho provato solo su 1.2, grazie per le specifiche!
Neemzy,

E poi c'è la modalità html5
rocketspacer il

5

Non vedo come questo problema sia legato a Facebook AJAX. In effetti il ​​problema si verifica anche con JavaScript disabilitato e accessi basati sul reindirizzamento puramente.

Uno scambio di esempio con 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#_  

Succede solo con Firefox anche per me.


4

L'aggiunta di questo alla mia pagina di reindirizzamento ha risolto il problema per me ...

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

1
questo provoca una modifica della posizione della finestra, iniziando un aggiornamento della pagina
rpearce

3

Con il router angolare e angolare, puoi risolvere questo problema

    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 ...
    });
});

non funziona qui - il percorso cambia prima dell'applicazione della regola ()
Maël Nison il

3

Se stai usando vue-router, puoi aggiungere all'elenco dei percorsi:

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

2

Recentemente è stato introdotto un cambiamento nel modo in cui Facebook gestisce i reindirizzamenti delle sessioni. Vedere "Modifica del comportamento di reindirizzamento della sessione" nel post sul blog di Operation Developer Love di questa settimana per l'annuncio.


1
Non sono sicuro di cosa si riferisca qui
user210504

2

Per me, faccio il reindirizzamento JavaScript su un'altra pagina per sbarazzarmi di #_=_. Le idee qui sotto dovrebbero funzionare. :)

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

questa non è una buona idea, penso perché stai creando molteplici richieste inutili
Jacek Pietal,

1

Una soluzione alternativa che ha funzionato per me (utilizzando Backbone.js) è stata l'aggiunta di "# /" alla fine dell'URL di reindirizzamento passato a Facebook. Facebook manterrà il frammento fornito e non aggiungerà il proprio "_ = _".

Al ritorno, Backbone rimuoverà la parte "# /". Per AngularJS, aggiungere "#!" all'URL di ritorno dovrebbe funzionare.

Si noti che l'identificatore di frammento dell'URL originale viene conservato al reindirizzamento (tramite i codici di stato HTTP 300, 301, 302 e 303) dalla maggior parte dei browser, a meno che l'URL di reindirizzamento abbia anche un identificatore di frammento. Questo sembra essere un comportamento raccomandato .

Se si utilizza uno script del gestore che reindirizza l'utente altrove, è possibile aggiungere qui "#" all'URL di reindirizzamento per sostituire l'identificatore di frammento con una stringa vuota.


1

So che questa risposta è in ritardo, ma se stai usando passportjs, potresti voler vedere questo.

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

Ho scritto questo middleware e l'ho applicato per esprimere l'istanza del server e l'URL originale che ho è senza "#_=_". Sembra che quando applichiamo l'istanza di passporJS come middleware all'istanza del server, non accetta quei caratteri, ma sono visibili solo sulla barra degli indirizzi dei nostri browser.


3
"# _ = _" è disponibile solo sul client. Recensione: en.wikipedia.org/wiki/Fragment_identifier
alditis,

1

Uso questo per cancellare anche il simbolo '#'.

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

0

Utilizzando Angular 2 (RC5) e percorsi basati su hash, faccio questo:

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

e

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

Per quanto ho capito, il =carattere nel percorso viene interpretato come parte della definizione dei parametri del percorso opzionale (vedere https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters ) , quindi non coinvolto nella corrispondenza del percorso.


0

Per utenti SDK PHP

Ho risolto il problema semplicemente rimuovendo la parte extra prima di inoltrare.

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

0

Ciò eliminerebbe i caratteri aggiunti all'URL

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

0

La soluzione più semplice e pulita per rimuovere "# _ = _" (PHP):

Invece di "header (" Location: xxx.php ");" usare "echo (" location.href = 'xxx.php'; ");"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.