Facebook Callback menambahkan '# _ = _' ke Return URL

479

Facebook callback telah mulai menambahkan #_=_garis bawah hash ke URL Kembali

Adakah yang tahu mengapa? Apa solusinya?

Zing ming
sumber
35
Adakah yang tahu bagaimana facebook menambahkan karakter-karakter ini? Facebook mengalihkan ke handler saya di mana saya kemudian menangani pengalihan ke url kembali, namun karakter masih ditambahkan ke url.
Ben Foster
4
@BenFoster Saya pikir Anda akan menemukan jika Anda menggunakan Fiddler atau yang serupa ketika FB dialihkan ke handler Anda, #_=_sudah ada di tempatnya, maka meskipun Anda melakukan Response.Redirectke tempat yang benar-benar ingin Anda lakukan, browser mempertahankan hash , itulah sebabnya mengapa hanya solusi sisi klien yang disarankan di bawah ini yang akan berfungsi.
AakashM
17
2017, what the zuck
Ejonas GGgg
6
Mei 2017, masih ....
Mirko
5
Maret 2018..ya masih terjadi
John Rogerson

Jawaban:

239

melalui Pembaruan Platform Facebook :

Ubah Perilaku Pengalihan Sesi

Minggu ini, kami mulai menambahkan fragmen # ____ = ____ ke redirect_uri ketika bidang ini dibiarkan kosong. Harap pastikan bahwa aplikasi Anda dapat menangani perilaku ini.

Untuk mencegah hal ini, atur redirect_uri dalam permintaan url login Anda seperti: (menggunakan Facebook php-sdk)

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

MEMPERBARUI

Di atas persis seperti yang dikatakan dokumentasi untuk memperbaikinya. Namun, solusi yang didokumentasikan Facebook tidak berfungsi. Silakan pertimbangkan untuk meninggalkan komentar di posting blog Pembaruan Platform Facebook dan ikuti bug ini untuk mendapatkan jawaban yang lebih baik. Sampai saat itu, tambahkan yang berikut ke tag kepala Anda untuk menyelesaikan masalah ini:

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

Atau alternatif yang lebih detail (terima kasih 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
sumber
10
bidang apa yang dibiarkan kosong? Ini sangat samar
user210504
11
@Ryan Perbarui hampir bekerja untuk saya, saya masih mendapatkan hash (/ #) pada akhirnya. Tidak senang dengan FB.
LenPopLilly
2
Saya masih mendapatkan / # juga. Adakah yang memperbarui di sini? untuk menghapus #
Tian Loon
6
Solusi ini akan menghapus hash: <script type = "text / javascript"> var idx = window.location.toString (). IndexOf ("# _ = _"); if (idx> 0) {window.location = window.location.toString (). substring (0, idx); } </script> Pastikan ini menjadi tag pertama di elemen head.
Gorgi Rankovski
1
Saya perhatikan laporan bug Anda di sini: developers.facebook.com/bugs/1424488987806270 Saya juga mencoba mencari "fragment request_uri" dengan hasil yang sama.
Ryan
115

TL; DR

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

Versi lengkap dengan petunjuk langkah demi langkah

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

    }

}

Selangkah demi selangkah:

  1. Kami hanya akan masuk ke blok kode jika fragmentadalah#_=_ .
  2. Periksa apakah browser mendukung HTML5 window.replaceState metode .
    1. Bersihkan URL dengan memisahkan # dan hanya mengambil bagian pertama.
    2. Katakan historyuntuk mengganti keadaan halaman saat ini dengan URL bersih. Ini mengubah entri riwayat saat ini daripada membuat yang baru. Artinya, tombol kembali dan maju akan berfungsi seperti yang Anda inginkan. ;-)
  3. Jika browser tidak mendukung metode riwayat HTML 5 yang mengagumkan, maka bersihkan URL sebaik mungkin dengan mengatur hash to string kosong. Ini adalah fallback yang buruk karena masih meninggalkan hash yang tertinggal (example.com/#) dan juga menambahkan entri riwayat, sehingga tombol kembali akan membawa Anda kembali ke #_-_.

Pelajari lebih lanjut tentang history.replaceState.

Pelajari lebih lanjut tentang window.location.

Paul Schwarz
sumber
2
Bekerja dengan baik untuk saya juga. Solusi lain menghilangkan parameter kueri.
AdeelMufti
Itu melakukan hal yang sama untuk google omniauth, jadi saya mendapatkan kesalahan tidak ada rute yang cocok, menambahkan # (hashtag) setelah meminta uri https: //.....herokua‌ pp.com/auth/google_oa‌ uth2 / callback? state = 1‌ 9feaacfe23423jh5jhhGS‌ DFwb419049ebb18dabdf8‌ & kode = 4 / glrY3-mSlTzwe‌ rwERTEG334eXcn3hOSxGu‌ c51BAlglPa4AU #
Shalafister's
Bekerja untuk saya lebih baik daripada solusi @Ryan, karena tidak menghapus kueri.
olivmir
Solusi ini bekerja lebih baik daripada solusi Ryan. Saya meneruskan beberapa parameter ke url setelah melalui otentikasi Facebook dan solusi Ryan, untuk beberapa alasan hanya menghapus setiap parameter dari url. Solusi ini berfungsi dengan baik dalam kasus saya.
BlueSun3k1
59

jika Anda ingin menghapus "#" yang tersisa dari 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
sumber
6
$ (window) .on ('load', function (e) {/ * kode likebeats * /} bekerja.
ISHITOYA Kentaro
1
saya menggunakan kode ini dengan mengubah e.preventDefault (); ke event.preventDefault ();
printf
Kode ini mengasumsikan jQuery, dan pendengar acara onWindowReady yang mengambil argumen e.
Jason Sperske
49

Ini diimplementasikan oleh Facebook dengan desain untuk alasan keamanan. Berikut penjelasan dari Eric Osgood, anggota Tim Facebook:

Ini telah ditandai sebagai 'oleh desain' karena mencegah potensi kerentanan keamanan.

Beberapa browser akan menambahkan fragmen hash dari URL ke akhir URL baru yang telah dialihkan (jika URL baru itu sendiri tidak memiliki fragmen hash).

Misalnya, jika example1.com mengembalikan pengalihan ke example2.com, maka browser yang menuju example1.com # abc akan pergi ke example2.com # abc, dan konten fragmen hash dari example1.com akan dapat diakses ke skrip pada example2 .com.

Karena dimungkinkan untuk memiliki satu aliran pengalihan otomatis ke yang lain, akan mungkin untuk memiliki data auth yang sensitif dari satu aplikasi yang dapat diakses oleh yang lain.

Ini dikurangi dengan menambahkan fragmen hash baru ke redirect URL untuk mencegah perilaku browser ini.

Jika estetika, atau perilaku sisi klien, dari URL yang dihasilkan menjadi perhatian, akan mungkin untuk menggunakan window.location.hash (atau bahkan pengalihan sisi-server Anda sendiri) untuk menghapus karakter yang menyinggung.

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

Mark Murphy
sumber
9
Ini adalah satu-satunya jawaban yang benar-benar menjelaskan mengapa ini terjadi, terima kasih, saya pikir saya akan meninggalkan karakter yang menyinggung di url saya sekarang karena saya tahu itu bukan masalah.
stephenmurdoch
1
Ini juga diterapkan oleh Tumblr dalam pengalihan mereka. (pada pertengahan '19) Terima kasih telah menunjuk ke penjelasan FB. Mudah dipecahkan dalam aplikasi Paspor sederhana dengan hanya mengarahkan redirect yang sukses ke "/ #" bukan hanya "/" (yang menjelaskan mengapa saya melihat lebih banyak jejak octothorps di web, saya pikir ...)
RL Brown
10

Tidak yakin mengapa mereka melakukan ini tetapi, Anda bisa menyiasatinya dengan mengatur ulang hash di bagian atas halaman Anda:

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

Anda juga dapat menentukan hash Anda sendiri pada redirect_uriparameter untuk panggilan balik Facebook, yang mungkin bisa membantu dalam keadaan tertentu misalnya /api/account/callback#home. Ketika Anda diarahkan kembali, setidaknya akan menjadi hash yang sesuai dengan rute yang diketahui jika Anda menggunakan backbone.js atau yang serupa (tidak yakin tentang jquery mobile).

pkiddie
sumber
8

Facebook menggunakan bingkai dan di dalamnya semuanya berfungsi menggunakan komunikasi AJAX. Masalah terbesar dalam hal ini adalah mempertahankan status halaman saat ini. Sejauh yang saya mengerti, Facebook memutuskan untuk menggunakan jangkar simulasi. Ini berarti jika Anda mengklik di suatu tempat, mereka mensimulasikan itu sebagai jangkar di dalam halaman Anda, dan ketika komunikasi AJAX dimulai, mereka juga mengubah bit jangkar URL Anda.

Solusi ini membantu Anda secara normal ketika Anda mencoba memuat ulang halaman (bukan ENTER, tekan F5), karena browser Anda mengirimkan seluruh URL dengan jangkar ke server Facebook. Karena itu Facebook mengambil status terbaru (apa yang Anda lihat) dan Anda kemudian dapat melanjutkan dari sana.

Ketika kembali panggilan #_=_itu berarti bahwa halaman itu dalam keadaan dasar sebelum meninggalkannya. Karena jangkar ini diuraikan oleh browser, Anda tidak perlu khawatir.

Sore Andor
sumber
2
Jika Anda memiliki kerangka kerja javascript seperti backbone atau bara itu adalah masalah karena semuanya setelah hash ditafsirkan oleh router
Rudi
1
Pengidentifikasi fragmen URL ("jangkar") tidak dikirim ke browser atas permintaan. Juga, pertanyaan ini tentang OAuth, bukan tentang situs desktop utama. Alasannya adalah keamanan OAuth - mencegah serangan karena membuat URI pengalihan berbahaya.
AndrewF
8

Sangat menjengkelkan, terutama untuk aplikasi yang mem-parsing URI dan tidak hanya membaca $ _GET ... Inilah hack yang saya lempar bersama ... Selamat menikmati!

<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
sumber
Berhati-hatilah dalam membuat asumsi saat mem-parsing data yang tidak Anda buat. Pengidentifikasi fragmen URI ditentukan sejak RFC 1738 (pada 1994) jadi jika Anda menggunakan parser URI yang benar, ini seharusnya tidak menjadi masalah.
AndrewF
6

Ini bisa menjadi semacam masalah serius jika Anda menggunakan kerangka kerja JS dengan URL hashbang (/ #! /), Misalnya Angular. Memang, Angular akan menganggap URL dengan fragmen non-hashbang sebagai tidak valid dan membuat kesalahan:

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

Jika Anda dalam kondisi seperti itu (dan mengalihkan ke root domain Anda), alih-alih melakukan:

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

Cukup lakukan:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest
neemzy
sumber
1.2+, ini bekerja dengan luar biasa. Untuk 1.0 dan di bawah ini gunakan window.location.hash = '';
Pradeep Mahdevu
1
Ya, saya hanya menguji ini pada 1.2, terima kasih untuk spesifikasinya!
neemzy
Dan kemudian ada mode html5
rocketspacer
5

Saya tidak melihat bagaimana masalah ini terkait dengan facebook AJAX. Bahkan masalah juga terjadi dengan JavaScript dinonaktifkan dan murni login berbasis ulang.

Contoh pertukaran dengan 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#_  

Terjadi hanya dengan Firefox untuk saya juga.

Sebastian Tusk
sumber
4

Menambahkan ini ke halaman pengalihan saya memperbaiki masalah bagi saya ...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}
neokio
sumber
1
ini menyebabkan perubahan lokasi jendela, memulai penyegaran halaman
rpearce
3

Dengan router ui angular dan angular, Anda dapat memperbaikinya

    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 ...
    });
});
pemberontak
sumber
tidak bekerja di sini - rute berubah sebelum aturan () diterapkan
Maël Nison
3

Jika Anda menggunakan vue-router, Anda dapat menambahkan ke daftar rute:

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

Perubahan baru-baru ini diperkenalkan dalam cara Facebook menangani pengalihan sesi. Lihat "Perubahan dalam Perilaku Pengalihan Sesi" di posting blog Cinta Pengembang Operasi minggu ini untuk pengumuman.

Dhiren Patel
sumber
1
Saya tidak yakin, apa yang dia maksudkan di sini
user210504
2

Bagi saya, saya melakukan pengalihan JavaScript ke halaman lain untuk menyingkirkan #_=_. Ide-ide di bawah ini harus bekerja. :)

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}
Eng Cy
sumber
ini bukan ide yang baik, saya pikir karena Anda membuat beberapa permintaan yang tidak berguna
Jacek Pietal
1

Solusi yang berhasil untuk saya (menggunakan Backbone.js), adalah menambahkan "# /" ke akhir URL pengalihan yang diteruskan ke Facebook. Facebook akan menyimpan fragmen yang disediakan, dan tidak menambahkan sendiri "_ = _".

Setelah kembali, Backbone akan menghapus bagian "# /". Untuk AngularJS, menambahkan "#!" ke URL kembali harus bekerja.

Perhatikan bahwa pengidentifikasi fragmen dari URL asli dipertahankan pada pengalihan (melalui kode status HTTP 300, 301, 302 dan 303) oleh sebagian besar browser, kecuali URL pengalihan juga memiliki pengidentifikasi fragmen. Perilaku ini sepertinya direkomendasikan .

Jika Anda menggunakan skrip handler yang mengarahkan ulang pengguna di tempat lain, Anda dapat menambahkan "#" ke URL pengalihan di sini untuk mengganti pengidentifikasi fragmen dengan string kosong.

Ivo Smits
sumber
1

Saya tahu balasan ini terlambat, tetapi jika Anda menggunakan passportjs, Anda mungkin ingin melihat ini.

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

Saya telah menulis middleware ini dan menerapkannya untuk mengekspresikan instance server, dan URL asli yang saya dapatkan adalah tanpa "#_=_". Sepertinya ketika kita menerapkan instance passporJS 'sebagai middleware ke instance server, itu tidak mengambil karakter tersebut, tetapi hanya terlihat pada bilah alamat browser kita.

Krishna
sumber
3
"# _ = _" hanya tersedia di klien. Ulasan: en.wikipedia.org/wiki/Fragment_identifier
alditis
1

Saya menggunakan ini, untuk menghapus simbol '#' juga.

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

Menggunakan Angular 2 (RC5) dan rute berbasis hash, saya melakukan ini:

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

dan

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

Sejauh yang saya mengerti, =karakter dalam rute ditafsirkan sebagai bagian dari definisi parameter rute opsional (lihat https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters ) , jadi tidak terlibat dalam pencocokan rute.

rcomblen
sumber
0

Untuk pengguna PHP SDK

Saya memperbaiki masalah hanya dengan menghapus bagian tambahan sebelum meneruskan.

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

Ini akan menghapus karakter yang ditambahkan ke url Anda

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

Solusi termudah dan bersih untuk menghapus "# _ = _" (PHP):

Alih-alih "tajuk (" Lokasi: xxx.php ");" untuk menggunakan "echo (" location.href = 'xxx.php'; ");"

pengguna3806621
sumber