Facebook Callback hängt '# _ = _' an die Rückgabe-URL an

479

Der Facebook-Rückruf hat begonnen, einen #_=_Hash-Unterstrich an die Rückgabe-URL anzuhängen

Weiß jemand warum? Was ist die Lösung?

zing ming
quelle
35
Irgendeine Idee, wie Facebook diese Charaktere anfügt? Facebook leitet zu meinem Handler weiter, wo ich dann die Weiterleitung zur Rückgabe-URL erledige, die Zeichen jedoch weiterhin an die URL angehängt werden.
Ben Foster
4
@BenFoster Ich denke, Sie werden feststellen, wenn Sie Fiddler oder ähnliches verwenden, dass, wenn FB zu Ihrem Handler umleitet, das vorhanden #_=_ist. Obwohl Sie ein Ziel festlegen, Response.Redirectwo Sie es tatsächlich tun möchten, behält der Browser den Hash bei , weshalb Es funktionieren nur die unten vorgeschlagenen clientseitigen Problemumgehungen.
AakashM
17
2017, was zum zuck
Ejonas GGgg
6
Mai 2017, noch ....
Mirko
5
März 2018 ... ja, es passiert immer noch
John Rogerson

Antworten:

239

über die Plattform-Updates von Facebook :

Änderung des Sitzungsumleitungsverhaltens

Diese Woche haben wir begonnen, dem redirect_uri ein Fragment # ____ = ____ hinzuzufügen, wenn dieses Feld leer bleibt. Stellen Sie sicher, dass Ihre App mit diesem Verhalten umgehen kann.

Um dies zu verhindern, setzen Sie redirect_uri in Ihrer Login-URL-Anfrage wie folgt: (mit Facebook php-sdk)

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

AKTUALISIEREN

Das Obige ist genau so, wie es in der Dokumentation angegeben ist , um dies zu beheben. Die dokumentierte Lösung von Facebook funktioniert jedoch nicht. Bitte hinterlassen Sie einen Kommentar im Blog-Beitrag zu Facebook Platform Updates und folgen Sie diesem Fehler , um eine bessere Antwort zu erhalten. Fügen Sie bis dahin Folgendes zu Ihrem Head-Tag hinzu, um dieses Problem zu beheben:

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

Oder eine detailliertere Alternative (danke 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
quelle
10
Welches Feld bleibt leer? Dies ist sehr kryptisch
user210504
11
@ Ryan Update funktioniert fast für mich, ich bekomme immer noch einen Hash (/ #) am Ende. Nicht glücklich mit FB.
LenPopLilly
2
Ich bekomme immer noch das / #. jemand hier aktualisieren? um die # zu entfernen
Tian Loon
6
Diese Lösung löscht den Hash: <script type = "text / javascript"> var idx = window.location.toString (). IndexOf ("# _ = _"); if (idx> 0) {window.location = window.location.toString (). substring (0, idx); } </ script> Stellen Sie nur sicher, dass dies das erste Tag im head-Element ist.
Gorgi Rankovski
1
Ich habe Ihren Fehlerbericht hier bemerkt: developer.facebook.com/bugs/1424488987806270 Ich habe auch versucht, "fragment request_uri" mit den gleichen Ergebnissen zu suchen.
Ryan
115

TL; DR

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

Vollversion mit Schritt-für-Schritt-Anleitung

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

    }

}

Schritt für Schritt:

  1. Wir werden nur dann in den Codeblock gelangen, wenn dies der Fall fragmentist #_=_.
  2. Überprüfen Sie, ob der Browser die HTML5- window.replaceStateMethode unterstützt.
    1. Bereinigen Sie die URL, indem Sie sie aufteilen #und nur den ersten Teil übernehmen.
    2. Weisen Sie historyan, den aktuellen Seitenstatus durch die saubere URL zu ersetzen. Dadurch wird der aktuelle Verlaufseintrag geändert, anstatt einen neuen zu erstellen. Dies bedeutet, dass die Schaltflächen Zurück und Vorwärts genau so funktionieren, wie Sie es möchten. ;-);
  3. Wenn der Browser die fantastischen HTML 5-Verlaufsmethoden nicht unterstützt, bereinigen Sie einfach die URL so gut wie möglich, indem Sie den Hash auf eine leere Zeichenfolge setzen. Dies ist ein schlechter Fallback, da immer noch ein nachfolgender Hash (example.com/#) übrig bleibt und außerdem ein Verlaufseintrag hinzugefügt wird, sodass Sie mit der Schaltfläche "Zurück" zurück zu gelangen #_-_.

Erfahren Sie mehr über history.replaceState.

Erfahren Sie mehr über window.location.

Paul Schwarz
quelle
2
Hat auch bei mir perfekt funktioniert. Die andere Lösung entfernt alle Abfrageparameter.
AdeelMufti
Es macht das gleiche für Google Omniauth, so dass ich einen Fehler bekomme, bei dem keine Route übereinstimmt. Nach der Anfrage wird # (Hashtag) angehängt. Uri https: //.....herokua‌ pp.com/auth/google_oa‌ uth2 / callback? state = 1‌ 9feaacfe23423jh5jhhGS‌ DFwb419049ebb18dabdf8‌ & code = 4 / glrY3-mSlTzwe‌ rwERTEG334eXcn3hOSxGu‌ c51BAlglPa4AU #
Shalafisters
Hat bei mir besser funktioniert als die Lösung von @Ryan, da die Abfrage nicht gelöscht wird.
Olivmir
Diese Lösung funktionierte besser als die von Ryan. Ich übergebe einige Parameter an die URL, nachdem sie die Facebook-Authentifizierung und Ryans Lösung durchlaufen hat. Aus irgendeinem Grund werden einfach alle Parameter aus der URL entfernt. Diese Lösung funktioniert in meinem Fall perfekt.
BlueSun3k1
59

Wenn Sie das verbleibende "#" aus der URL entfernen möchten

$(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
quelle
6
$ (window) .on ('load', Funktion (e) {/ * likebeats 'Code * /} funktioniert.
ISHITOYA Kentaro
1
Ich benutze diesen Code durch Änderung e.preventDefault (); zu event.preventDefault ();
Druck vom
Dieser Code setzt jQuery voraus und ein onWindowReady-Ereignis-Listener übernimmt das Argument e.
Jason Sperske
49

Dies wurde von Facebook aus Sicherheitsgründen mit Absicht implementiert. Hier ist die Erklärung von Eric Osgood, einem Mitglied des Facebook-Teams:

Dies wurde als "beabsichtigt" gekennzeichnet, da es eine potenzielle Sicherheitslücke verhindert.

Einige Browser hängen das Hash-Fragment von einer URL an das Ende einer neuen URL an, zu der sie umgeleitet wurden (wenn diese neue URL selbst kein Hash-Fragment enthält).

Wenn beispielsweise example1.com eine Umleitung zu example2.com zurückgibt, wechselt ein Browser zu example1.com # abc zu example2.com # abc, und auf den Inhalt des Hash-Fragments von example1.com kann ein Skript in example2 zugreifen .com.

Da es möglich ist, dass ein Authentifizierungsfluss zu einer anderen umgeleitet wird, können vertrauliche Authentifizierungsdaten von einer App auf eine andere zugegriffen werden.

Dies wird durch Anhängen eines neuen Hash-Fragments an die Umleitungs-URL verringert, um dieses Browserverhalten zu verhindern.

Wenn die Ästhetik oder das clientseitige Verhalten der resultierenden URL von Bedeutung ist, können Sie mithilfe von window.location.hash (oder sogar einer eigenen serverseitigen Weiterleitung) die fehlerhaften Zeichen entfernen.

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

Mark Murphy
quelle
9
Dies ist die einzige Antwort, die tatsächlich erklärt, warum dies passiert. Danke, ich denke, ich werde die beleidigenden Zeichen in meinen URLs belassen, jetzt wo ich weiß, dass sie kein Problem sind.
Stephenmurdoch
1
Dies wird auch von Tumblr in deren Weiterleitungen implementiert. (ab Mitte '19) Danke, dass Sie auf die FB-Erklärung hingewiesen haben. Einfach in einer simplen Passport-App zu lösen, indem lediglich die erfolgreiche Weiterleitung auf "/ #" anstatt nur auf "/" verweist (was erklärt, warum ich im Web mehr nachlaufende Oktothorps sehe, denke ich ...)
RL Brown
10

Sie sind sich nicht sicher, warum sie dies tun, aber Sie können dies umgehen, indem Sie den Hash oben auf Ihrer Seite zurücksetzen:

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

Sie können auch Ihren eigenen Hash für den redirect_uriParameter für den Facebook-Rückruf angeben , was unter bestimmten Umständen hilfreich sein kann, z /api/account/callback#home. Wenn Sie zurückgeleitet werden, handelt es sich zumindest um einen Hash, der einer bekannten Route entspricht, wenn Sie backbone.js oder ähnliches verwenden (bei jquery mobile nicht sicher).

pkiddie
quelle
8

Facebook verwendet einen Frame und in ihm funktioniert alles über AJAX-Kommunikation. Das größte Problem in diesem Fall ist die Beibehaltung des aktuellen Seitenstatus. Soweit ich weiß, hat Facebook beschlossen, simulierte Anker zu verwenden. Das heißt, wenn Sie irgendwo geklickt haben, simulieren sie dies als Anker innerhalb Ihrer Seite, und wenn die AJAX-Kommunikation beginnt, ändern sie auch das Ankerbit Ihrer URL.

Diese Lösung hilft Ihnen normalerweise, wenn Sie versuchen, die Seite neu zu laden (nicht ENTER, drücken Sie F5 ), da Ihr Browser die gesamte URL mit Ankern an den Facebook-Server sendet. Daher nimmt Facebook den neuesten Status (was Sie sehen) auf und Sie können von dort aus fortfahren.

Wenn der Rückruf damit zurückkehrt #_=_, bedeutet dies, dass sich die Seite vor dem Verlassen in ihrem Grundzustand befand. Da dieser Anker vom Browser analysiert wird, müssen Sie sich darüber keine Sorgen machen.

Sándor Tóth
quelle
2
Wenn Sie ein Javascript-Framework wie Backbone oder Ember haben, ist dies ein Problem, da alles nach dem Hash vom Router interpretiert wird
Rudi
1
URL-Fragment-IDs ("Anker") werden auf Anfrage nicht an den Browser gesendet . Außerdem bezieht sich diese Frage auf OAuth und nicht auf die Haupt-Desktop-Site. Der Grund dafür ist die OAuth-Sicherheit , die Angriffe aufgrund der Erstellung eines böswilligen Umleitungs-URI verhindert.
AndrewF
8

Sehr ärgerlich, besonders für Apps, die den URI analysieren und nicht nur das $ _GET lesen ... Hier ist der Hack, den ich zusammengeschmissen habe ... Viel Spaß!

<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
quelle
Seien Sie vorsichtig, wenn Sie Annahmen analysieren, die Sie nicht erstellen. URI-Fragment-IDs wurden bereits in RFC 1738 (1994) angegeben. Wenn Sie also einen korrekten URI-Parser verwenden, sollte dies niemals ein Problem sein.
AndrewF
6

Dies kann zu einem ernsthaften Problem werden, wenn Sie ein JS-Framework mit Hashbang-URLs (/ #! /) Verwenden, z. B. Angular. In der Tat betrachtet Angular URLs mit einem Nicht-Hashbang-Fragment als ungültig und gibt einen Fehler aus:

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

Wenn Sie sich in einem solchen Fall befinden (und zu Ihrem Domain-Stamm umleiten), anstatt Folgendes zu tun:

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

Einfach machen:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest
neemzy
quelle
1.2+, das funktioniert super. Verwenden Sie für 1.0 und niedriger window.location.hash = '';
Pradeep Mahdevu
1
Ja, ich habe dies nur auf 1.2 getestet, danke für die Spezifikation!
Neemzy
Und dann gibt es HTML5-Modus
Rocketspacer
5

Ich sehe nicht, wie dieses Problem mit Facebook AJAX zusammenhängt. Tatsächlich tritt das Problem auch bei deaktiviertem JavaScript und rein umleitungsbasierten Anmeldungen auf.

Ein Beispiel für einen Austausch mit 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#_  

Passiert nur mit Firefox auch für mich.

Sebastian Tusk
quelle
4

Das Hinzufügen zu meiner Weiterleitungsseite hat das Problem für mich behoben ...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}
neokio
quelle
1
Dies führt zu einer Änderung der Fensterposition, wodurch eine
Seitenaktualisierung eingeleitet wird
3

Mit eckigen und eckigen UI-Routern können Sie dies beheben

    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 ...
    });
});
Rebellier
quelle
funktioniert hier nicht - die Route ändert sich, bevor die Regel () angewendet wird
Maël Nison
3

Wenn Sie einen Vue-Router verwenden, können Sie die Liste der Routen anhängen:

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

Kürzlich wurde eine Änderung eingeführt, wie Facebook mit Sitzungsumleitungen umgeht. Die Ankündigung finden Sie im Blog-Beitrag " Operation Developer Love " dieser Woche unter "Änderung des Sitzungsumleitungsverhaltens" .

Dhiren Patel
quelle
1
Ich bin nicht sicher, worauf er sich hier bezieht
user210504
2

Für mich mache ich eine JavaScript-Umleitung auf eine andere Seite, um sie loszuwerden #_=_. Die folgenden Ideen sollten funktionieren. :) :)

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}
Eng Cy
quelle
Dies ist keine gute Idee, denke ich, weil Sie mehrere nutzlose Anfragen erstellen
Jacek Pietal
1

Eine Problemumgehung, die für mich (mit Backbone.js) funktioniert hat, war das Hinzufügen von "# /" am Ende der an Facebook übergebenen Weiterleitungs-URL. Facebook behält das bereitgestellte Fragment bei und fügt kein eigenes "_ = _" hinzu.

Bei der Rückkehr entfernt Backbone den Teil "# /". Fügen Sie für AngularJS "#!" zur Rückgabe URL sollte funktionieren.

Beachten Sie, dass die Fragmentkennung der ursprünglichen URL bei der Umleitung (über die HTTP-Statuscodes 300, 301, 302 und 303) von den meisten Browsern beibehalten wird, es sei denn, die Umleitungs-URL verfügt auch über eine Fragmentkennung. Dies scheint ein empfohlenes Verhalten zu sein .

Wenn Sie ein Handler-Skript verwenden, das den Benutzer an eine andere Stelle umleitet, können Sie hier "#" an die Umleitungs-URL anhängen, um die Fragment-ID durch eine leere Zeichenfolge zu ersetzen.

Ivo Smits
quelle
1

Ich weiß, dass diese Antwort zu spät ist, aber wenn Sie passportjs verwenden, möchten Sie dies möglicherweise sehen.

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

Ich habe diese Middleware geschrieben und auf die Express-Serverinstanz angewendet, und die ursprüngliche URL, die ich habe, ist ohne die "#_=_". Sieht so aus, als würden wir die Instanz von passporJS als Middleware auf die Serverinstanz anwenden. Diese Zeichen werden nicht verwendet, sondern sind nur in der Adressleiste unserer Browser sichtbar.

Krishna
quelle
3
"# _ = _" ist nur auf dem Client verfügbar. Bewertung: en.wikipedia.org/wiki/Fragment_identifier
Alditis
1

Ich benutze dieses, um auch das Symbol '#' zu löschen.

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

Mit Angular 2 (RC5) und Hash-basierten Routen mache ich Folgendes:

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

und

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

Soweit ich weiß, wird das =Zeichen in der Route als Teil der optionalen Definition der Routenparameter interpretiert (siehe https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters ). , also nicht am Routenabgleich beteiligt.

rcomblen
quelle
0

Für PHP SDK Benutzer

Ich habe das Problem einfach behoben, indem ich das zusätzliche Teil vor dem Weiterleiten entfernt habe.

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

Dies würde die an Ihre URL angehängten Zeichen entfernen

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

Die einfachste und sauberste Lösung zum Entfernen von "# _ = _" (PHP):

Anstelle von "header (" Location: xxx.php ");" um "echo (" location.href = 'xxx.php'; ") zu verwenden;"

user3806621
quelle