Cookie và Session trong Django
Mục lục- Cookie và Session trong Django
- Nguồn gốc của Cookie
- Định nghĩa Cookie
- Ứng dụng đơn giản của Cookie
- Hiệu ứng khi tắt Cookie khi đăng nhập vào blog
- Xem Cookie
- Thiết lập Cookie
- Lấy Cookie
- Thiết lập Cookie
- Tham số:
- Xóa Cookie
- Tạo một dự án Django đơn giản, sử dụng Cookie để xác thực trạng thái đăng nhập người dùng
- Nguồn gốc của Session
- Các phương thức liên quan đến Session trong Django
- Phân tích quy trình Session
- Cấu hình Session trong Django
- Sử dụng Session đơn giản để thực hiện xác thực đăng nhập
- Xem cấu hình toàn cục from django.conf import global_settings
Nguồn gốc của Cookie
Mọi người đều biết rằng giao thức HTTP là không trạng thái.
Không trạng thái có nghĩa là mỗi yêu cầu đều độc lập, tình trạng và kết quả của nó không có mối quan hệ trực tiếp với các yêu cầu trước và sau,
nó không bị ảnh hưởng trực tiếp bởi tình trạng phản hồi của các yêu cầu trước đó, cũng không ảnh hưởng trực tiếp đến tình trạng phản hồi của các yêu cầu sau.
Một câu thú vị để mô tả là cuộc đời chỉ như lần gặp đầu tiên, đối với máy chủ, mỗi yêu cầu đều là mới.
Trạng thái có thể hiểu là dữ liệu được tạo ra giữa client và server trong một phiên, và không trạng thái có nghĩa là dữ liệu này không được lưu giữ.
Dữ liệu được tạo ra trong phiên lại là dữ liệu chúng ta cần lưu giữ, tức là cần "giữ trạng thái". Do đó, Cookie ra đời trong bối cảnh như vậy.
Định nghĩa Cookie
Cookie cụ thể là một đoạn thông tin nhỏ, đó là các cặp khóa-giá trị được máy chủ gửi ra và lưu trữ trên trình duyệt,
khi truy cập máy chủ lần sau, trình duyệt sẽ tự động mang theo các cặp khóa-giá trị này để máy chủ trích xuất thông tin hữu ích.
1. Được máy chủ yêu cầu trình duyệt thiết lập
2. Trình duyệt lưu trữ cục bộ
3. Tự động mang theo khi truy cập lần sau
Nguyên lý hoạt động của cookie là: nội dung được máy chủ tạo ra, trình duyệt nhận được yêu cầu và lưu trữ cục bộ; khi trình duyệt truy cập lại,
trình duyệt sẽ tự động mang theo Cookie, nhờ vậy máy chủ có thể xác định "ai" là thông qua nội dung của Cookie.
Đơn giản来说: cookie là các cặp khóa-giá trị được lưu trữ trên trình duyệt cục bộ
-
Ứng dụng đơn giản của Cookie
1. Đăng nhập (chỉ là một ứng dụng của cookie)
2. Lưu thói quen duyệt web như: phân trang trình duyệt, hiển thị số lượng dữ liệu (chỉ là một ứng dụng của cookie)
3. Đếm số phiếu bầu đơn giản (chỉ là một ứng dụng của cookie)
-
Hiệu ứng khi tắt Cookie khi đăng nhập vào blog
-
Xem Cookie
Thiết lập Cookie
-
Lấy Cookie
request.COOKIES['key']
request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)
Các tham số của phương thức get_signed_cookie:
- default: Giá trị mặc định
- salt: Muối mã hóa
- max_age: Thời gian hết hạn được kiểm soát từ phía máy chủ
-
Thiết lập Cookie
resp = HttpResponse(...)
resp = render(request, ...)
resp.set_cookie(key,value,...)
resp.set_signed_cookie(key,value,salt='muối mã hóa',...)
-
Tham số:
- key, khóa
- value='', giá trị
- max_age=None, thời gian hết hạn
- expires=None, thời gian hết hạn (IE yêu cầu expires, vì vậy hãy đặt nó nếu chưa được đặt.)
- path='/', đường dẫn mà Cookie có hiệu lực, / biểu thị đường dẫn gốc, đặc biệt: cookie của đường dẫn gốc có thể được truy cập bởi bất kỳ trang nào của url
- domain=None, tên miền mà Cookie có hiệu lực
- secure=False, truyền qua https
- httponly=False chỉ có thể truyền qua giao thức http, không thể lấy được bằng JavaScript (không tuyệt đối, có thể lấy được bằng packet capture hoặc bị ghi đè)
-
Xóa Cookie
def logout(request):
resp = redirect("/login/")
resp.delete_cookie("user") # Xóa giá trị cookie user đã được thiết lập trước đó trên trình duyệt của người dùng
return resp
Tạo một dự án Django đơn giản, sử dụng Cookie để xác thực trạng thái đăng nhập người dùng
- login.html
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Đăng nhập</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>
Tên người dùng: <input type="text" name="username">
</p>
<p>
Mật khẩu: <input type="password" name="pwd">
</p>
<p>{{ error }}</p>
<button>Gửi</button>
</form>
</body>
</html>
- views.py
from django.views import View # Nhập mô-đun view dựa trên lớp
from django.shortcuts import render, redirect, HttpResponse# Nhập bộ ba response
class Login(View): # View xử lý logic đăng nhập
def get(self, request, *args, **kwargs): # Xử lý phương thức GET
return render(request, 'login.html') # Nếu là yêu cầu GET (làm mới trang, v.v.), vẫn là trang đăng nhập
def post(self, request, *args, **kwargs): # Xử lý phương thức POST
username = request.POST.get('username') # Tài khoản được gửi từ form
pwd = request.POST.get('pwd') # Mật khẩu được gửi từ form
if username == 'admin' and pwd == '123456': # Kiểm tra tài khoản và mật khẩu đơn giản
url = request.GET.get('return_url') # Lấy return_url, thông tin đường dẫn sau
if url: # Nếu có thông tin đường dẫn
resp = redirect(url) # Chuyển hướng đến đường dẫn cần truy cập
else:
resp = redirect('/dashboard/') # Nếu không, chuyển hướng mặc định đến trang dashboard
resp.set_cookie('user_authenticated', 'true') # Sử dụng cookie để xác định trạng thái đăng nhập
return resp # Phản hồi yêu cầu
return render(request, 'login.html', {'error': 'Tên người dùng hoặc mật khẩu không đúng'})# Sai tài khoản/mật khẩu, chuyển hướng đến login.html và hiển thị thông báo
def authentication_required(func): # Decorator để kiểm tra trạng thái đăng nhập của người dùng
def inner(request, *args, **kwargs):
is_authenticated = request.COOKIES.get('user_authenticated') # Lấy trạng thái đăng nhập
current_url = request.path_info # Thông tin đường dẫn của trang truy cập
if is_authenticated != 'true': # Nếu trạng thái không phải 'true' thì chưa đăng nhập
return redirect('/login/?return_url={}'.format(current_url))# Chuyển hướng đến trang login và ghép thông tin trang trước đó vào đường dẫn
result = func(request, *args, **kwargs) # Nếu trạng thái là 'true', thực thi view function
return result # Phản hồi yêu cầu
return inner
@authentication_required # Decorator kiểm tra trạng thái đăng nhập
def dashboard(request): # Xử lý yêu cầu route dashboard
return HttpResponse('Trang chủ') # Mô phỏng đơn giản trang chủ
@authentication_required # Decorator kiểm tra trạng thái đăng nhập
def profile(request): # Xử lý yêu cầu route profile
return HttpResponse('Trang hồ sơ') # Mô phỏng đơn giản trang hồ sơ
-
Sai tài khoản/mật khẩu khi đăng nhập
-
Truy cập profile cũng đăng nhập thành công và chuyển đến trang profile
-
Đăng nhập trực tiếp từ trang login, mặc định quay về trang dashboard
Nguồn gốc của Session
Mặc dù Cookie đã giải quyết nhu cầu "giữ trạng thái" đến một mức độ nhất định, nhưng do Cookie tự bản thân chỉ hỗ trợ tối đa 4096 byte,
và Cookie được lưu trữ trên client, có thể bị chặn hoặc đánh cắp, vì vậy cần có một thứ mới, nó có thể hỗ trợ nhiều byte hơn,
và được lưu trữ trên máy chủ, có độ bảo mật cao hơn. Đó chính là Session.
Vấn đề là, dựa trên đặc điểm không trạng thái của giao thức HTTP, máy chủ hoàn toàn không biết người truy cập là "ai". Vậy thì Cookie ở trên sẽ đóng vai trò cầu nối.
Chúng ta có thể gán một ID duy nhất cho mỗi Cookie của client, như vậy khi người dùng truy cập, thông qua Cookie, máy chủ sẽ biết người đến là "ai".
Sau đó chúng ta lại dựa vào ID Cookie khác nhau, lưu trữ một khoảng thời gian dữ liệu riêng tư trên máy chủ, như "tài khoản mật khẩu" v.v.
Tóm lại: Cookie bù đắp cho sự thiếu trạng thái của HTTP, giúp máy chủ biết người đến là "ai"; nhưng Cookie được lưu dưới dạng văn bản cục bộ,
độ bảo mật kém; vì vậy chúng ta nhận dạng người dùng khác nhau thông qua Cookie, và lưu trữ thông tin riêng tư và văn bản vượt quá 4096 byte trong Session.
Ngoài ra, Cookie và Session được đề cập ở trên thực chất là những thứ chung, không giới hạn bởi ngôn ngữ và framework.
#Đơn giản来说, Session là các cặp khóa-giá trị được lưu trữ trên máy chủ (phải phụ thuộc vào cookie)
#Tại sao cần có session
1Cookie được lưu trên trình duyệt cục bộ
2Kích thước và số lượng bị giới hạn
Các phương thức liên quan đến Session trong Django
# Lấy
request.session['k1']# request.session[key] = value #['key'] không lấy được sẽ báo lỗi, nên sử dụng get để lấy, không có giá trị trả về None
request.session.get('k1',None)# request.session.get(key)
# Thiết lập
request.session['k1'] = 123
request.session.setdefault('k1',123) # Nếu đã tồn tại thì không thiết lập
# Xóa
del request.session['k1']# Xóa
request.session.delete()# Xóa tất cả dữ liệu Session của phiên hiện tại
# Kiểu dữ liệu nào được sử dụng để thiết lập giá trị, kiểu dữ liệu đó cũng được sử dụng để kiểm tra
Ví dụ: if is_login != '1': Khi thiết lập là chuỗi '1' mới có thể viết như vậy, giá trị của cookie phải ở dạng chuỗi.
# Tất cả khóa, giá trị, cặp khóa-giá trị
request.session.keys()
request.session.values()
request.session.items()
"""
Các phiên bản mysql cũ hơn có thể sử dụng
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
"""
# Khóa của phiên session
request.session.session_key
# Xóa tất cả dữ liệu Session có ngày hết hạn nhỏ hơn ngày hiện tại
request.session.clear_expired()
# Kiểm tra xem khóa session có tồn tại trong cơ sở dữ liệu hay không
request.session.exists("session_key")
# Xóa tất cả dữ liệu Session của phiên hiện tại
request.session.delete()
# Xóa dữ liệu Session hiện tại và xóa Cookie của phiên.
request.session.flush()
Điều này được sử dụng để đảm bảo dữ liệu phiên trước không thể được truy cập bởi trình duyệt của người dùng nữa
Ví dụ, hàm django.contrib.auth.logout() sẽ gọi nó.
# Thiết lập thời gian hết hạn cho Session và Cookie #Thời gian hết hạn mặc định là 2 tuần
request.session.set_expiry(value)
* Nếu value là số nguyên, session sẽ hết hạn sau số giây đó.
* Nếu value là datatime hoặc timedelta, session sẽ hết hạn sau thời gian này.
* Nếu value là 0, session sẽ hết hạn khi người dùng đóng trình duyệt.
* Nếu value là None, session sẽ phụ thuộc vào chính sách hết hạn session toàn cục.
Phân tích quy trình Session
Cấu hình Session trong Django
#Django mặc định hỗ trợ Session, bên trong cung cấp 5 loại Session cho nhà phát triển sử dụng.
1. Session cơ sở dữ liệu
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # Engine (mặc định)
2. Session cache
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # Engine
SESSION_CACHE_ALIAS = 'default' # Bí danh cache được sử dụng (mặc định là cache bộ nhớ, cũng có thể là memcache),
bí danh này phụ thuộc vào cài đặt cache
3. Session file
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # Engine
SESSION_FILE_PATH = None # Đường dẫn file cache, nếu là None,
thì sử dụng địa chỉ tạm thời được lấy từ module tempfile tempfile.gettempdir()
4. Cache + cơ sở dữ liệu
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # Engine
5. Session Cookie được mã hóa
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # Engine
Các cài đặt chung khác:
SESSION_COOKIE_NAME = "sessionid" # Khóa của Session cookie khi lưu trên trình duyệt,
tức là: sessionid=chuỗi ngẫu nhiên (mặc định)
SESSION_COOKIE_PATH = "/" # Đường dẫn lưu Session cookie (mặc định)
SESSION_COOKIE_DOMAIN = None # Tên miền lưu Session cookie (mặc định)
SESSION_COOKIE_SECURE = False # Có truyền cookie qua https không (mặc định)
SESSION_COOKIE_HTTPONLY = True # Có phải Session cookie chỉ hỗ trợ truyền qua http không (mặc định)
SESSION_COOKIE_AGE = 1209600 # Ngày hết hạn của Session cookie (2 tuần) (mặc định)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Có phải đóng trình duyệt sẽ làm Session hết hạn không (mặc định)
SESSION_SAVE_EVERY_REQUEST = False # Có phải mỗi yêu cầu đều lưu Session không, mặc định chỉ lưu sau khi sửa đổi (mặc định)
-
Sử dụng Session đơn giản để thực hiện xác thực đăng nhập
from django.views import View # Nhập mô-đun view dựa trên lớp
from django.shortcuts import render, redirect, HttpResponse # Nhập bộ ba response
class Login(View): # View xử lý logic đăng nhập
def get(self, request, *args, **kwargs): # Xử lý phương thức GET
return render(request, 'login.html') # Nếu là yêu cầu GET (làm mới trang, v.v.), vẫn là trang đăng nhập
def post(self, request, *args, **kwargs): # Xử lý phương thức POST
username = request.POST.get('username') # Tài khoản được gửi từ form
pwd = request.POST.get('pwd') # Mật khẩu được gửi từ form
if username == 'admin' and pwd == '123456': # Kiểm tra tài khoản và mật khẩu đơn giản
url = request.GET.get('return_url') # Lấy return_url, thông tin đường dẫn sau
if url: # Nếu có thông tin đường dẫn
resp = redirect(url) # Chuyển hướng đến đường dẫn cần truy cập
else:
resp = redirect('/dashboard/') # Nếu không, chuyển hướng mặc định đến trang dashboard
request.session['user_status'] = 'authenticated' # Sử dụng session để xác định trạng thái đăng nhập
return resp # Phản hồi yêu cầu
return render(request, 'login.html', {'error': 'Tên người dùng hoặc mật khẩu không đúng'}) # Sai tài khoản/mật khẩu, chuyển hướng đến login.html và hiển thị thông báo
def authentication_required(func): # Decorator để kiểm tra trạng thái đăng nhập của người dùng
def inner(request, *args, **kwargs):
current_url = request.path_info # Thông tin đường dẫn của trang truy cập
status = request.session.get('user_status')# Lấy trạng thái
if status != 'authenticated': # Nếu trạng thái không phải 'authenticated' thì chưa đăng nhập
return redirect('/login/?return_url={}'.format(current_url)) # Chuyển hướng đến trang login và ghép thông tin trang trước đó vào đường dẫn
result = func(request, *args, **kwargs) # Nếu trạng thái là 'authenticated', thực thi view function
return result # Phản hồi yêu cầu
return inner
@authentication_required # Decorator kiểm tra trạng thái đăng nhập
def dashboard(request): # Xử lý yêu cầu route dashboard
return HttpResponse('Trang chủ') # Mô phỏng đơn giản trang chủ
@authentication_required # Decorator kiểm tra trạng thái đăng nhập
def profile(request): # Xử lý yêu cầu route profile
return HttpResponse('Trang hồ sơ') # Mô phỏng đơn giản trang hồ sơ
-
Xem cấu hình toàn cục from django.conf import global_settings
-
Cơ sở dữ liệu văn bản đi kèm của Django không thể thay đổi thời gian