Saya menulis aplikasi web di Angular di mana autentikasi ditangani oleh token JWT, yang berarti bahwa setiap permintaan memiliki header "Autentikasi" dengan semua informasi yang diperlukan.
Ini berfungsi dengan baik untuk panggilan REST, tetapi saya tidak mengerti bagaimana saya harus menangani tautan unduhan untuk file yang dihosting di backend (file berada di server yang sama tempat layanan web dihosting).
Saya tidak dapat menggunakan <a href='...'/>
tautan biasa karena mereka tidak akan membawa header apa pun dan autentikasi akan gagal. Sama untuk berbagai mantra window.open(...)
.
Beberapa solusi yang saya pikirkan:
- Buat tautan unduhan sementara yang tidak aman di server
- Teruskan informasi otentikasi sebagai parameter url dan tangani kasus secara manual
- Dapatkan data melalui XHR dan simpan sisi klien file.
Semua hal di atas kurang memuaskan.
1 adalah solusi yang saya gunakan sekarang. Saya tidak menyukainya karena dua alasan: pertama ini tidak ideal dari segi keamanan, kedua berfungsi tetapi memerlukan cukup banyak pekerjaan terutama di server: untuk mengunduh sesuatu saya perlu memanggil layanan yang menghasilkan "acak "url, menyimpannya di suatu tempat (mungkin di DB) untuk beberapa waktu, dan mengembalikannya ke klien. Klien mendapatkan url, dan menggunakan window.open atau serupa dengannya. Saat diminta, url baru harus memeriksa apakah masih valid, lalu mengembalikan datanya.
2 tampaknya setidaknya banyak pekerjaan.
3 tampaknya banyak pekerjaan, bahkan menggunakan perpustakaan yang tersedia, dan banyak masalah potensial. (Saya perlu menyediakan bilah status unduhan saya sendiri, memuat seluruh file dalam memori dan kemudian meminta pengguna untuk menyimpan file secara lokal).
Tugasnya tampaknya cukup mendasar, jadi saya bertanya-tanya apakah ada sesuatu yang lebih sederhana yang dapat saya gunakan.
Saya belum tentu mencari solusi "cara Angular". Javascript biasa akan baik-baik saja.
sumber
Jawaban:
Berikut cara untuk mendownloadnya di klien menggunakan atribut download , fetch API , dan URL.createObjectURL . Anda akan mengambil file menggunakan JWT, mengubah payload menjadi blob, meletakkan blob tersebut menjadi objectURL, menyetel sumber tag anchor ke objectURL itu, dan mengklik objectURL itu dalam javascript.
Nilai
download
atribut akan menjadi nama file akhirnya. Jika diinginkan, Anda dapat menambang nama file yang diinginkan dari header respons disposisi konten seperti yang dijelaskan dalam jawaban lain .sumber
Teknik
Berdasarkan saran Matias Woloski dari Auth0, penginjil JWT yang terkenal ini, saya menyelesaikannya dengan membuat permintaan yang ditandatangani dengan Hawk .
Mengutip Woloski:
Di sini Anda memiliki contoh teknik ini, digunakan untuk tautan aktivasi.
backend
Saya membuat API untuk menandatangani url unduhan saya:
Permintaan:
Tanggapan:
Dengan URL yang ditandatangani, kita bisa mendapatkan file tersebut
Permintaan:
Tanggapan:
frontend (oleh jojoyuji )
Dengan cara ini Anda dapat melakukan semuanya dengan satu klik pengguna:
sumber
Alternatif untuk pendekatan "fetch / createObjectURL" dan "download-token" yang telah disebutkan adalah Formulir POST standar yang menargetkan jendela baru . Setelah browser membaca header lampiran pada respons server, itu akan menutup tab baru dan mulai mengunduh. Pendekatan yang sama ini juga bekerja dengan baik untuk menampilkan sumber daya seperti PDF di tab baru.
Ini memiliki dukungan yang lebih baik untuk browser lama dan menghindari keharusan mengelola jenis token baru. Ini juga akan memiliki dukungan jangka panjang yang lebih baik daripada autentikasi dasar pada URL, karena dukungan untuk nama pengguna / kata sandi pada url sedang dihapus oleh browser .
Di sisi klien kami menggunakan
target="_blank"
untuk menghindari navigasi bahkan dalam kasus kegagalan, yang sangat penting untuk SPA (aplikasi satu halaman).Peringatan utamanya adalah validasi JWT sisi server harus mendapatkan token dari data POST dan bukan dari header . Jika framework Anda mengelola akses ke penangan rute secara otomatis menggunakan header Authentication, Anda mungkin perlu menandai penangan Anda sebagai tidak diautentikasi / anonim sehingga Anda dapat memvalidasi JWT secara manual untuk memastikan otorisasi yang tepat.
Formulir dapat dibuat secara dinamis dan segera dihancurkan sehingga dibersihkan dengan benar (catatan: ini dapat dilakukan dalam JS biasa, tetapi JQuery digunakan di sini untuk kejelasan) -
Cukup tambahkan data tambahan yang perlu Anda kirimkan sebagai input tersembunyi dan pastikan data tersebut ditambahkan ke formulir.
sumber
Saya akan membuat token untuk diunduh.
Dalam angular buat permintaan yang diautentikasi untuk mendapatkan token sementara (katakanlah satu jam) lalu tambahkan ke url sebagai parameter get. Dengan cara ini Anda dapat mengunduh file dengan cara apa pun yang Anda suka (window.open ...)
sumber
Solusi tambahan: menggunakan otentikasi dasar. Meskipun memerlukan sedikit pekerjaan di backend, token tidak akan terlihat di log dan tidak ada penandatanganan URL yang harus diterapkan.
Sisi klien
Contoh URL bisa jadi:
http://jwt:<user jwt token>@some.url/file/35/download
Contoh dengan token dummy:
http://jwt:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwIiwibmFtZSI6IiIsImlhdCI6MH0.KsKmQOZM-jcy4l_7NFsv1lWfpH8ofniVCv75ZRQrWno@some.url/file/35/download
Anda kemudian dapat memasukkan ini ke dalam
<a href="...">
atauwindow.open("...")
- browser menangani sisanya.Sisi server
Penerapannya di sini terserah Anda, dan bergantung pada penyiapan server Anda - tidak terlalu jauh berbeda dengan menggunakan
?token=
parameter kueri.Dengan menggunakan Laravel, saya mengambil rute yang mudah dan mengubah kata sandi otentikasi dasar menjadi
Authorization: Bearer <...>
header JWT , membiarkan middleware otentikasi normal menangani sisanya:sumber