240512_Django实现基于cookie与session的用户登录
用户登录鉴权一直都是一个头疼的点。3月就开始着手搞了(了解基本原理,以及分布式的服务器情况,在一台服务器上登录后,其他服务器如果没有同步这条session记录的话,用户又需要重新登录,比如换了国家使用应用。而jwt服务端不需要保存,服务器验证是不是自己发行的token就行了)
4月头上也实现出来了,现在来记录下。
可以使用django自带的
1 | from django.contrib.auth import authenticate, login, logout |
但不知道这些自带函数到底做了什么,这时就需要去看源码了。
先来看Django自带的功能
当创建Django项目,migrate了后,初始数据库自带有auth_user表,django_session表。
然后就主要使用Django内置的用户认证系统: django.contrib.auth
关于User表:
- 可以直接使用自带的auth_user用户表(就是我们createsuperuser也是写入这个表里,这个表其实直接继承自AbstractUser)
from django.contrib.auth.models import AuthUser - 也可以自己定义用户表,但继承自内置用户类AbstractUser
class User(AbstractUser):以此增加一些自定义字段
以上都可以利用到Django内置的用户认证系统: django.contrib.auth,包括authenticate, login, logout, create_user…等方法
如果用户表是class User(models.Model):而非继承于AbstractUser的话,那所有的一切都需要自己实现,就像做PFN的oa题一样。
所以我可能倾向用继承AbstractUser自定义用户表,而不是直接用auth_user表
OK,我们先来写一个注册函数吧,在先不自定义用户表的情况下。
1 | from django.contrib.auth.models import User as AuthUser # 使用自带的auth_user表 |
用django-ninja自带的docs测试下
1 | curl -X 'POST' \ |
Response body
1 | { |
然后数据库里也有了这条记录

create_user()会自动哈希pwd存到数据库里
然后来尝试自定义User表:
1 | from django.contrib.auth.models import AbstractUser |
注意:按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,我现在使用我新定义的User表来做用户认证。django.contrib.auth的login…函数就作用在自定义表而不是auth_user表了
相当于默认的设置 AUTH_USER_MODEL = ‘auth.user’
1 | AUTH_USER_MODEL = 'builtin_auth.User' |
迁移一下数据库
1 | python manage.py makemigrations |
出问题了就删掉migrations目录下的所有0001_initial.py之类的迁移文件&数据库文件
原来数据库中的auth_user表没了,只有builtin_auth_user表了,而且有自定义的phone字段
所以在第一次migrate时就要确定好User表用什么
然后修改register函数
1 | # from django.contrib.auth.models import User as AuthUser # 使用自带的auth_user表 |
仅仅就是换了个数据库表,改了表名
然后数据都在builtin_auth_user表里了
OK,用户已经注册后然后来处理login
register就仅仅是往数据库加一条用户数据
login若就是简单基于session的话,那就先检验前端发来的username和pwd能不能匹配得上(前端发来的pwd哈希后==用户表里存着的username对应的已哈希了的pwd),验证成功就session表里添加一条记录表明用户已登录,然后发给前端sessionID(一般前端设置cookie,也可以随便前端存在哪)
核心就是数据库加一条session记录,把session记录的id(也可以理解为token)发给前端,以便让前端之后再发请求时带着这个token(此处即sessionID)来保持登录(cookie作为http请求头),能和数据库里存的对得上
前端或者postman把cookie给清空了,就丢失了token(sessionID),就丢失了对这个会话的标示,那就需要重新登录了,即使后端数据库可能还存着原先的sessionID
还有不少的网站,可能给游客用户也发一个sessionID,然后前端一般就把这个sessionID存在cookie里,来记录这个游客的会话,服务端还可以设置其他的cookie比如对某个endpoint的访问次数。浏览器会把存着的cookie都放到http请求头里。
logout就把django_session里的对应记录删除
但实际浏览器的cookie在刷新后会丢失
1 | import axios from "axios"; |
可能还是自带auth的cookie设置问题,因为我自己后端设置的response.set_cookie("cookie", "delicious"),浏览器刷新还是在的
⚠️注意⚠️
axios.post("http://127.0.0.1:8000/api/login/" 浏览器刷新后cookie丢失
axios.post("http://localhost:8000/api/login/" 浏览器刷新后cookie还在
即cookie的Domin要是localhost,不懂为什么127.0.0.1丢失了
axios.defaults.baseURL = “http://localhost:8000“; 那改成localhost就好了
就是因为node起的服务器地址是localhost:5173,同源的cookie自然好设置。127.0.0.1都跨站了就需要cookie的跨站处理,什么cookie的SameSite
本质原因在于cookie的SameSite属性有问题:
this set cookie didn t specify a samesite
https://andrewlock.net/understanding-samesite-cookies/
https://stackoverflow.com/questions/46288437/set-cookies-for-cross-origin-requests
==根本还是Django自带的登录功能的cookie设置不对,设置了samesite: “Lax”==
最好还是自己实现吧,还能把session存在redis缓存里,亲自给前端发cookie
全都自定义实现
可以参考django.contrib.auth的源码
- Title: 240512_Django实现基于cookie与session的用户登录
- Author: Haoliang Tang
- Created at : 2024-05-12 00:00:00
- Updated at : 2025-04-29 23:49:43
- Link: https://hl-tang.github.io/2024/05/12/240512_Django实现基于cookie与session的用户登录/
- License: This work is licensed under CC BY-NC-SA 4.0.