Django使用session管理(cookie)实现了一个用户登录和会话保持功能。如果需求不太复杂可以使用Django默认的登录功能。
1 安装django-cors-headers
首先需要安装django-cors-headers
pip install django-cors-headers
2 在settings中配置
需要按照django-cors-headers 官方说明进行配置。https://github.com/adamchainz/django-cors-headers
主要是以下几项:
from corsheaders.defaults import default_headers
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
# 这里写的是前端的地址,比如8080
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"http://127.0.0.1:9000",
]
# 上面这个配置可以用下面的替换,直接允许所有的源
CORS_ALLOW_ALL_ORIGINS = True
# 这个是允许携带cookie
CORS_ALLOW_CREDENTIALS = True
# 配置header允许的字段
CORS_ALLOW_HEADERS = [
*default_headers,
'withCredentials',
]
SESSION_COOKIE_SAMESITE = "None"
SESSION_COOKIE_SECURE = True
3 在视图中使用Django提供的登录函数
https://docs.djangoproject.com/en/5.0/topics/auth/default/#django.contrib.auth.views.LoginView
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
这里注意,只有header中Content-Type
是x-www-form-urlencoded
才可以这样解析,如果是application/json
, 需要通过下面的方式:
data = json.loads(request.body)
username = data['username']
password = data['password']
4 使用fetch进行登录
在前端通过fetch或者axios发送请求,这里以fetch为例:
fetch(url, {
headers: {
'X-CSRFToken': csrftoken, //这个是可选的,如果禁用了csftoken则不需要。
'Content-Type': 'x-www-form-urlencoded', //这里可以是application/json,后端需要方式二获取参数
withCredentials: true //跨域时携带cookie
},
credentials: 'include', //要求携带cookie,否则无法维持会话
body: JSON.stringify({
username: xxx,
password: xxx
})
}).
then(res=>res.json()).
then(resJson=>{
console.log(resJson) //这里处理登录结果
})
我们也可以包装为一个函数:
import Cookies from 'js-cookie'
const sendRequest = (url, method, data)=>{
const csrftoken = Cookies.get('csrftoken')
const options = {
method: method,
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/json', //这里可以是application/json,后端需要方式二获取参数
withCredentials: true //跨域时携带cookie
},
credentials: 'include', //要求携带cookie,否则无法维持会话
body: JSON.stringify(data)
}
if(method != 'GET' && data) {
options.body = JSON.stringify(data)
}
return fetch(`http://localhost:8000/${url}`, options)
}
5 验证登录是否成功
如果登录成功,则前端发送的请求都会带有一个user,后端可以这样获取:
def my_view(request):
id = request.user.id
如果登录失败,则前端获取的id为None,用户为匿名用户。
遇到的问题
- “Origin checking failed … does not match any trusted origins”
禁用csrf_token,具体做法:
- 建立一个middleware:
class DisableCSRFMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
setattr(request, '_dont_enforce_csrf_checks', True)
response = self.get_response(request)
return response
- 在settings中启用:
MIDDLEWARE = [
'django.middleware.common.CommonMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'myapp.middle.DisableCSRFMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
- 使用非本机地址无法保持登录状态。
一开始以为是GET无法cookie,后来改成POST还是同样问题。最后发现在http下传输会有安全维问题,需要在settings.py设置这两项:
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_SECURE = False # 允许http传输cookie
在localhost下,即使http也是安全的,可以传输。