Bagaimana mengakhiri sesi karena tidak ada aktivitas di Django?

94

Aplikasi Django kita memiliki persyaratan manajemen sesi berikut.

  1. Sesi berakhir saat pengguna menutup browser.
  2. Sesi berakhir setelah periode tidak aktif.
  3. Mendeteksi saat sesi berakhir karena tidak aktif dan menampilkan pesan yang sesuai kepada pengguna.
  4. Peringatkan pengguna tentang sesi yang akan datang berakhir beberapa menit sebelum akhir periode tidak aktif. Bersamaan dengan peringatan tersebut, berikan pengguna opsi untuk memperpanjang sesi mereka.
  5. Jika pengguna sedang mengerjakan aktivitas bisnis yang panjang dalam aplikasi yang tidak melibatkan permintaan yang dikirim ke server, sesi tidak boleh timeout.

Setelah membaca dokumentasi, kode Django dan beberapa kiriman blog yang berhubungan dengan ini, saya mendapatkan pendekatan implementasi berikut.

Persyaratan 1
Persyaratan ini mudah diterapkan dengan menyetel SESSION_EXPIRE_AT_BROWSER_CLOSE ke True.

Persyaratan 2
Saya telah melihat beberapa rekomendasi untuk menggunakan SESSION_COOKIE_AGE untuk mengatur periode berakhirnya sesi. Tetapi metode ini memiliki masalah berikut.

  • Sesi selalu berakhir di akhir SESSION_COOKIE_AGE meskipun pengguna aktif menggunakan aplikasi. (Ini dapat dicegah dengan menyetel sesi kedaluwarsa ke SESSION_COOKIE_AGE pada setiap permintaan menggunakan middleware khusus atau dengan menyimpan sesi pada setiap permintaan dengan menyetel SESSION_SAVE_EVERY_REQUEST ke true. Tetapi masalah selanjutnya tidak dapat dihindari karena penggunaan SESSION_COOKIE_AGE.)

  • Karena cara kerja cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE dan SESSION_COOKIE_AGE sama-sama eksklusif, yaitu cookie kedaluwarsa pada penutupan browser atau pada waktu kedaluwarsa yang ditentukan. Jika SESSION_COOKIE_AGE digunakan dan pengguna menutup browser sebelum cookie kedaluwarsa, cookie dipertahankan dan membuka kembali browser akan mengizinkan pengguna (atau siapa pun) ke dalam sistem tanpa diautentikasi ulang.

  • Django hanya mengandalkan kuki yang ada untuk menentukan apakah sesi aktif. Itu tidak memeriksa tanggal kedaluwarsa sesi yang disimpan dengan sesi.

Metode berikut dapat digunakan untuk mengimplementasikan persyaratan ini dan untuk mengatasi masalah yang disebutkan di atas.

  • Jangan setel SESSION_COOKIE_AGE.
  • Setel tanggal kedaluwarsa sesi menjadi 'waktu saat ini + periode tidak aktif' pada setiap permintaan.
  • Timpa process_request di SessionMiddleware dan periksa masa berakhir sesi. Buang sesi jika telah kedaluwarsa.

Persyaratan 3
Saat kami mendeteksi bahwa sesi telah kedaluwarsa (di SessionMiddleware kustom di atas), setel atribut pada permintaan untuk menunjukkan sesi berakhir. Atribut ini dapat digunakan untuk menampilkan pesan yang sesuai kepada pengguna.

Persyaratan 4
Gunakan JavaScript untuk mendeteksi ketidakaktifan pengguna, memberikan peringatan dan juga opsi untuk memperpanjang sesi. Jika pengguna ingin memperpanjang, kirim pulsa tetap ke server untuk memperpanjang sesi.

Persyaratan 5
Gunakan JavaScript untuk mendeteksi aktivitas pengguna (selama operasi bisnis yang panjang) dan mengirim pulsa tetap hidup ke server untuk mencegah sesi kedaluwarsa.


Pendekatan implementasi di atas tampak sangat rumit dan saya bertanya-tanya apakah mungkin ada metode yang lebih sederhana (terutama untuk Persyaratan 2).

Setiap wawasan akan sangat dihargai.

Akbar ibrahim
sumber
3
1 untuk memberikan solusi terperinci
Don
Ada middleware yang dapat melakukan apa yang Anda butuhkan. di github dan di pypi
gbutler
1
"Karena cara kerja cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE dan SESSION_COOKIE_AGE sama-sama eksklusif yaitu cookie kedaluwarsa pada penutupan browser atau pada waktu kedaluwarsa yang ditentukan. Jika SESSION_COOKIE_AGE digunakan dan pengguna menutup browser sebelum cookie kedaluwarsa, cookie akan dipertahankan dan dibuka kembali browser akan mengizinkan pengguna (atau siapa pun) ke dalam sistem tanpa diautentikasi ulang. " Koreksi saya jika saya salah, tetapi ini tampaknya tidak benar lagi di versi Django yang lebih baru? (Setidaknya 1.5+)
Botond Béres
1
"Django hanya mengandalkan cookie yang ada untuk menentukan apakah sesi aktif. Ini tidak memeriksa tanggal kedaluwarsa sesi yang disimpan dengan sesi." Ini tidak benar lagi.
knaperek

Jawaban:

44

Ini idenya ... Tutup sesi di browser dengan SESSION_EXPIRE_AT_BROWSER_CLOSEsetelannya. Kemudian setel stempel waktu di sesi pada setiap permintaan seperti itu.

request.session['last_activity'] = datetime.now()

dan tambahkan middleware untuk mendeteksi jika sesi telah kedaluwarsa. sesuatu seperti ini harus menangani seluruh proses ...

from datetime import datetime
from django.http import HttpResponseRedirect

class SessionExpiredMiddleware:
    def process_request(request):
        last_activity = request.session['last_activity']
        now = datetime.now()

        if (now - last_activity).minutes > 10:
            # Do logout / expire session
            # and then...
            return HttpResponseRedirect("LOGIN_PAGE_URL")

        if not request.is_ajax():
            # don't set this for ajax requests or else your
            # expired session checks will keep the session from
            # expiring :)
            request.session['last_activity'] = now

Kemudian Anda hanya perlu membuat beberapa url dan tampilan untuk mengembalikan data yang relevan ke panggilan ajax mengenai berakhirnya sesi.

saat pengguna memilih untuk "memperbarui" sesi, boleh dikatakan, yang harus Anda lakukan adalah menyetel requeset.session['last_activity']waktu saat ini lagi

Jelas sekali kode ini hanyalah permulaan ... tetapi akan membawa Anda ke jalur yang benar

Jiaaro
sumber
Saya hanya bersikap skeptis di sini, tetapi menurut saya ini tidak if not request.is_ajax()sepenuhnya aman. Tidak bisakah seseorang yang memegang sesi sebelum kedaluwarsa memalsukan / mengirim panggilan ajax dan menjaga sesi tetap berjalan?
notbad.jpeg
2
@ notbad.jpeg: secara umum "aktivitas" mudah dipalsukan. Seseorang yang menahan sesi dan terus mengirim permintaan hanya aktif.
RemcoGerlich
Ini jawaban yang bagus. Middleware adalah alat yang sangat kurang dimanfaatkan dalam pengembangan Django.
Jamie Counsell
31

Saya cukup baru menggunakan Django.

Saya ingin membuat sesi kedaluwarsa jika pengguna yang login menutup browser atau dalam keadaan menganggur (waktu tunggu tidak aktif) untuk beberapa waktu. Ketika saya mencari tahu di Google, pertanyaan SOF ini muncul lebih dulu. Terima kasih untuk jawaban yang bagus, saya mencari sumber untuk memahami bagaimana middlewares bekerja selama siklus permintaan / tanggapan di Django. Itu sangat membantu.

Saya akan menerapkan middleware khusus ke dalam kode saya mengikuti jawaban teratas di sini. Tapi saya masih agak curiga karena jawaban terbaik disini sudah diedit tahun 2011. Saya meluangkan lebih banyak waktu untuk mencari sedikit dari hasil pencarian terbaru dan muncul dengan cara yang sederhana.

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True

Saya tidak memeriksa browser lain kecuali chrome. 1. Sesi kedaluwarsa ketika saya menutup browser meskipun SESSION_COOKIE_AGE disetel. 2. Hanya ketika saya menganggur selama lebih dari 10 detik, sesi A berakhir. Terima kasih kepada SESSION_SAVE_EVERY_REQUEST, kapan pun Anda muncul permintaan baru, Sesi ini akan disimpan dan waktu tunggu pembaruan habis untuk kedaluwarsa

Untuk mengubah perilaku default ini, setel pengaturan SESSION_SAVE_EVERY_REQUEST ke True. Ketika disetel ke True, Django akan menyimpan sesi ke database pada setiap permintaan tunggal.

Perhatikan bahwa cookie sesi hanya dikirim ketika sesi telah dibuat atau dimodifikasi. Jika SESSION_SAVE_EVERY_REQUEST adalah True, cookie sesi akan dikirim pada setiap permintaan.

Demikian pula, bagian cookie sesi yang kedaluwarsa diperbarui setiap kali cookie sesi dikirim.

django manual 1.10

Saya hanya meninggalkan jawaban sehingga beberapa orang yang termasuk baru di Django seperti saya tidak menghabiskan banyak waktu untuk mencari solusi seperti yang saya lakukan.

Jayground
sumber
26

django-session-security melakukan hal itu ...

... dengan persyaratan tambahan: jika server tidak merespons atau penyerang memutuskan koneksi internet: bagaimanapun juga itu harus kedaluwarsa.

Penolak: Saya memelihara aplikasi ini. Tapi saya sudah menonton utas ini untuk waktu yang sangat, sangat lama :)

jpic
sumber
1
aplikasi keren - dirancang dengan baik dan dibangun dengan baik. bagus, kode bersih ... terima kasih.
nicorellius
Jika pengguna menutup browser atau tab (tanpa logout) saat keluar, apakah masih memaksa pengguna untuk logout? Apakah itu menangani kondisi ini?
Mehmet Kagan Kayaalp
Itu akan ditangani oleh cookie sesi http murni, bukan?
jpic
10

Satu cara mudah untuk memenuhi persyaratan kedua Anda adalah dengan menyetel nilai SESSION_COOKIE_AGE di settings.py ke jumlah detik yang sesuai. Misalnya:

SESSION_COOKIE_AGE = 600      #10 minutes.

Namun, dengan hanya melakukan ini sesi akan berakhir setelah 10 menit terlepas dari apakah pengguna menunjukkan beberapa aktivitas atau tidak. Untuk mengatasi masalah ini, waktu kedaluwarsa dapat diperpanjang secara otomatis (untuk tambahan 10 menit lagi) setiap kali pengguna melakukan segala jenis permintaan dengan kalimat berikut:

request.session.set_expiry(request.session.get_expiry_age())
Fernando Martin
sumber
2
SESSION_COOKIE_AGE = 600 Ini akan memperpanjang usia sesi dengan setiap permintaan halaman baru atau penyegaran halaman
Aseem
1
Saya mengonfirmasi bahwa pengaturan saja SESSION_COOKIE_AGEsudah cukup dan bahwa permintaan apa pun (mengirim cookie sesi) akan secara otomatis menyegarkan kadaluwarsa cookie sesi.
bruno desthuiers
3

Anda juga dapat menggunakan fungsi build in stackoverflow

SESSION_SAVE_EVERY_REQUEST = True
mexekanez
sumber
Sama sekali tidak terkait - ini untuk memaksa penyimpanan sesi (bukan "penyegaran cookie sesi") pada setiap permintaan tanpa memeriksa apakah sesi telah diubah.
bruno desthuiers
3

Dalam permintaan pertama, Anda dapat mengatur masa berakhir sesi sebagai

self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds 

Dan saat menggunakan access_key dan token,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
ikan nila
sumber