1.环境准备
第一步,我们需要安装Django中处理API、JWT和跨域的核心库
1.API:RESTful规范。安装库 pip install django djangorestframework
- djangorestframework (DRF): 强大的 API 开发框架。
2.JWT:pip install djangorestframework-simplejwt
- djangorestframework-simplejwt : 专门为 DRF 设计的 JWT 插件,帮我们搞定 Token 生成、验证和刷新。
3.跨域:pip install django-cors-headers
- django-cors-headers : 处理前端跨域请求(前端在 localhost:5173,后端在 localhost:8000,必须配置这个)。

第二步,创建Django项目,创建app执行相应登录、注册、token刷新机制。
在工具中点击:

输入指令startapp user。在这里创建的app,会自动在app列表中帮我们添加

如果是手动在终端输入指令 python manage.py startapp user,就需要我们手动的在app列表中添加对应app。
2.设计用户模型
注意 :本教程为了演示原理,密码采用了 明文存储 。在生产环境中, 严禁 明文存储密码!请务必使用 Django 自带的 make_password 或 set_password 进行哈希加密存储。
打开 backend/user/models.py :
方法1:使用 @property 来添加DRF框架所需要的字段
python
from django.db import models
class UserInfo(models.Model):
# 由于指定了AUTH_USER_MODEL
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = [] # 创建超级用户时需要的必填字段(除了 username 和 password)
username = models.CharField(max_length=32,unique= True)
password = models.CharField(max_length=32)
email = models.EmailField(unique= True,null=True)
age = models.IntegerField(null=True)
sex = models.CharField(max_length=32,null=True)
status = models.IntegerField(
null=True,
choices=[(0, '正常'), (1, '停用')],
default=0,
verbose_name="帐号状态(0正常 1停用)",
db_comment="帐号状态(0正常 1停用)"
)
# 添加 simplejwt 所需的属性
@property
def is_active(self):
# 0 表示正常,1 表示停用
return self.status == 0
@property
def is_authenticated(self):
return True
@property
def is_anonymous(self):
return False
class Meta:
db_table = 'userinfo'
verbose_name = '用户信息'
verbose_name_plural = '用户信息'
方法2:直接在数据库字段中定义这些属性
python
from django.db import models
class UserInfo(models.Model):
# 由于指定了AUTH_USER_MODEL
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = [] # 创建超级用户时需要的必填字段(除了 username 和 password)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=32)
email = models.EmailField(unique=True, null=True)
age = models.IntegerField(null=True)
sex = models.CharField(max_length=32, null=True)
# 【改动点1】直接在数据库中定义 is_active
# 替代了原来的 status 字段,更符合 Django 原生规范
is_active = models.BooleanField(
default=True,
verbose_name="账号状态",
help_text="指明用户是否被视为活跃。以反选代替删除账号。"
)
# 【改动点2】is_authenticated 和 is_anonymous 不需要存数据库
# 它们描述的是"当前对象的身份状态",恒定逻辑如下:
@property
def is_authenticated(self):
"""
总是返回 True。这是告诉 Django:"只要你拿到了这个 UserInfo 实例,
说明这肯定是一个已登录的合法用户。"
"""
return True
@property
def is_anonymous(self):
"""
总是返回 False。这是告诉 Django:"这不是一个匿名游客对象。"
"""
return False
class Meta:
db_table = 'userinfo'
verbose_name = '用户信息'
verbose_name_plural = '用户信息'
对于3个方法的解释:
这三个属性是 Django 认证系统(Authentication System)的核心协议,DRF 和 SimpleJWT 都是基于这个协议来工作的。
1. is_active
- 含义 : "这个账号还能用吗?"
- 作用 :
- **登录拦截 :**SimpleJWT 在签发 Token 前,以及 DRF 在验证 Token 后,都会检查这个属性。如果 is_active=False ,即使用户名密码正确,或者 Token 签名正确,系统也会拒绝请求,返回 401 Unauthorized 。
- **业务场景 :**用户离职、账号被封禁、邮箱未验证。
- 实现建议 :
- 方法1 :用 @property 动态判断 status == 0 。优点是不用改数据库结构,复用已有业务逻辑。
- 方法2 :直接存 True/False 。优点是查询快,可以直接 filter(is_active=True)
2. is_authenticated
- 含义 : "不管你是谁,你到底登录了没?"
- 作用 :
- **权限控制 :**DRF 的 IsAuthenticated 权限类就是靠检查 request.user.is_authenticated 来决定是否放行的。
- 返回值 :
- 登录用户(User 对象) :必须返回 True 。
- 匿名用户(AnonymousUser 对象) :Django 有一个特殊的 AnonymousUser 类(代表未登录的游客),它的这个属性永远返回 False 。
- **注意 :**这个属性绝对不应该设计成数据库字段!因为它描述的是 当前请求的状态 (Context),而不是用户的固有属性。只要是一个有效的用户实例,它天然就是"已认证实体",所以你直接返回 True 是完全正确的。Django 默认的 AbstractBaseUser 也是把它实现为一个只读属性(property),恒为 True 。
3. is_anonymous
- 含义: "你是游客吗?"
- 作用 :
- 它是 is_authenticated 的反义词。
- 登录用户 :必须返回 False 。
- 匿名用户 :必须返回 True 。
- 注意 : 同样不应该设计成数据库字段!这也是一个逻辑属性。对于任何真实存在的 UserInfo 对象来说,它肯定不是匿名用户,所以硬编码返回 False 是标准做法。
3.全局配置
打开 backend/backend/settings.py ,我们需要修改 5 个地方:
1.注册应用:将DRF,SimplejWT、跨域插件添加到应用列表中去。
python
INSTALLED_APPS = [
# ... 原有应用
'rest_framework', # 注册 DRF
'rest_framework_simplejwt', # 注册 SimpleJWT
'corsheaders', # 注册跨域插件
'user', # 注册我们自己的 core 应用
]

2.激活中间件
python
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 【新增】必须放在最前面或尽量靠前
'django.middleware.security.SecurityMiddleware',
# ... 其他中间件
]

3.配置自定义用户模型 告诉 Django :"不要用自带的 User 了,用我写的 user.UserInfo "。
python
AUTH_USER_MODEL = "user.UserInfo"
4.配置 DRF 和 JWT 这里我们定义: API 默认必须登录才能访问,认证方式是 JWT。
python
from datetime import timedelta # 记得导入 timedelta
REST_FRAMEWORK = {
# 默认认证方式:使用 SimpleJWT 的 JWTAuthentication
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
# 默认权限:允许任何人访问 (我们会在具体 View 中覆盖这个,或者设为 IsAuthenticated 默认更安全)
# 这里为了方便注册接口,先设为 AllowAny,但在受保护接口手动加 IsAuthenticated
"DEFAULT_PERMISSION_CLASSES": (
"rest_framework.permissions.AllowAny",
),
}
SIMPLE_JWT = {
# Access Token 有效期 5 分钟
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
# Refresh Token 有效期 7 天
"REFRESH_TOKEN_LIFETIME": timedelta(days=7),
# 前端请求头格式: Authorization: Bearer <token>
# 注意 Bearer 和 <token> 之间必须有一个空格 。
"AUTH_HEADER_TYPES": ("Bearer",),
}
5.配置跨域 ( CORS ) 允许前端访问后端。
注意的是末尾不要加斜杠 / 。这也是一个常见的坑。
python
CORS_ALLOWED_ORIGINS = [
"http://localhost:5173", # Vue 默认端口
"http://127.0.0.1:5173",
]
4.编写序列化器
序列化器 (Serializer) 的作用 :它是数据转换器。
-
输入时 :把前端传来的 JSON (用户名、密码) 校验并转成 Python 对象。
-
输出时 :把 Python 对象 (User) 转成 JSON 返回给前端。
在 backend/user/ 下新建 serializers.py :
python
from rest_framework import serializers
from user.models import UserInfo
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = ['username', 'password'] # 只需要填写用户名和密码
extra_kwargs = {
'password': {'write_only': True}
}
5.编写视图
视图负责处理具体的 HTTP 请求。
打开 backend/user/views.py :
python
from rest_framework import permissions,status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken
from user.models import UserInfo
from user.serializers import UserSerializer
# 注册接口
class RegisterView(APIView):
permission_classes = [permissions.AllowAny] # 允许任何人访问
def post(self,request):
user = UserInfo.objects.filter(username=request.data.get('username')).first()
if user:
return Response({'message':"用户已存在",'code':400},status = status.HTTP_400_BAD_REQUEST)
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message':"注册成功",'code':200,'data':{'username':serializer.data.get('username')}},status = status.HTTP_200_OK)
return Response({'message':"注册失败",'code':400,'data':serializer.errors},status = status.HTTP_400_BAD_REQUEST)
#登录接口
class LoginView(APIView):
permission_classes = [permissions.AllowAny] # 允许任何人访问
def post(self,request):
data = request.data
username = data.get('username')
password = data.get('password')
user = UserInfo.objects.filter(username=username,password=password).first()
if user:
refresh = RefreshToken.for_user(user)
token = str(refresh.access_token)
print(token)
return Response({'message':"登陆成功",'code':200,'data':{'token':token}},status = status.HTTP_200_OK)
return Response({'message':"用户名或密码错误",'code':400},status = status.HTTP_400_BAD_REQUEST)
#测试接口
class TestView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self,request):
user = request.user
print(user.username)
return Response({'message':"测试成功",'code':200},status = status.HTTP_200_OK)
6.配置路由
最后,我们需要把这些视图挂载到 URL 上
1.应用级路由 ( backend/user/urls.py ,新建此文件):
python
from django.urls import path
from .views import RegisterView, LoginView, TestView
urlpatterns = [
path('register/', RegisterView.as_view()),
path('login/', LoginView.as_view()),
path('test/', TestView.as_view())
]
2.项目级路由 ( backend/backend/urls.py ):
python
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('user/', include('user.urls'))
]
7.生成数据并运行
python
# 1. 生成迁移文件 (检测 models 变化)
python manage.py makemigrations
# 2. 执行迁移 (创建表)
python manage.py migrate
# 3. 启动服务器
python manage.py runserver
8.效果展示(使用Apipost)
相关接口:
--注册接口:http://127.0.0.1:8000/user/register/
--登录接口:http://127.0.0.1:8000/user/login/
--测试接口:http://127.0.0.1:8000/user/test/
1.首先我们进行注册,注册需要填写用户名和密码。

可以看到我们已经注册成功,在数据库中也能找到对应的用户。
2.然后我们进行登录,登录成功之后会返回access_token,我们将该token保存起来

登录成功之后会返回access_token值,我们将该值设置在测试接口的请求头中。去进行测试。
3.测试token是否有效
要注意的是要将头部添加Bearer。我们可以看到此时测试是成功的。

接下来我们修改一下token值,也就是给一个错误的token值。

此时请求就失败了。我们在后端输出中也能看出是401错误。
然后我们再等过了超时时间进行测试,token是否会过期,这里我们设置的access_token的有效期是5分钟,等5分钟之后重新测试。

我们发现,在access_token有效期内,我们的请求都不会被拦截。但是当access_token有效期超出了我们设置的5分钟之后我们再进行请求就会发生401的错误。之后我们可以拿refresh_token去刷新我们的access_token,就不需要重新登录了(续权)。但是在这章我们没有介绍token的续权。续权操作,在前端的响应拦截器中,当识别到401错误的时候,就拿refresh_token,通相应接口来拿到新的access_token,完成token的续权。
9.小结
通过本文,我们从零开始搭建了一套基于 Django REST Framework (DRF) 和 SimpleJWT 的用户认证系统。我们不仅完成了环境配置、跨域处理,还深入探讨了自定义用户模型(Custom User Model)中 is_active 、 is_authenticated 等关键属性的底层原理,这在实际开发中是避免报错的关键细节。
核心知识点回顾:
1. SimpleJWT 集成 : 如何配置 JWT 的生命周期与认证头。
2. 自定义模型陷阱 : 在使用非标准 User 模型时,必须补全 Django 认证系统所需的协议属性(Property)。
3. 鉴权流程闭环 :从注册 -> 登录签发 Token -> 携带 Token 访问受保护接口 -> Token 校验。
虽然我们成功实现了"门禁系统"(鉴权),但这只是后端开发的起点。DRF 还有更多强大的功能等待探索,比如 视图集 (ViewSets) 如何简化代码、 权限类 (Permissions) 如何做细粒度的对象级控制、以及如何利用 Refresh Token 实现无感自动续签。这些内容我们将在后续的文章中继续深入。
需要注意的是,本实战主要演示了鉴权流程的跑通。在生产环境中,你还需要考虑:
- 密码安全 :务必使用哈希加密存储(如 make_password )。
- 权限控制 :结合 Permissions 实现不同角色的访问控制。
- 体验优化 :在前端实现 Token 的自动刷新机制(token续权)。
希望这篇文章能帮你快速搭建起安全的认证后端,为你的项目打下坚实基础!
