4、用户模块设计:用户模型设计、注册功能实现、登录与认证机制
用户模块,说白了就是整个电商系统的「大门」。
我做了这么多年项目,见过太多团队一上来就写业务代码,结果用户注册登录这块漏洞百出。嗯,今天咱们就把这扇门给砌结实了。
4.1 用户模型设计
先聊聊模型设计。我个人习惯,用户表一定要预留扩展字段,别等上线了再改表结构,那滋味可不好受。
一个电商系统的用户模型,核心字段大概这些:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BigInteger | 主键,自增 |
| username | VARCHAR(50) | 用户名,唯一索引 |
| password_hash | VARCHAR(128) | 加密后的密码 |
| VARCHAR(100) | 邮箱,唯一 | |
| phone | VARCHAR(20) | 手机号 |
| avatar_url | VARCHAR(255) | 头像地址 |
| status | TINYINT | 0-未激活 1-正常 2-禁用 |
| created_at | DATETIME | 注册时间 |
| updated_at | DATETIME | 更新时间 |
我的小习惯: 加一个
extra_data JSON字段,用来存一些不确定的扩展信息。比如用户偏好、推荐人ID之类的。别问我为什么,问就是被需求变更坑过。
用 Django 的模型来写,大概长这样:
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
email = models.EmailField(unique=True)
phone = models.CharField(max_length=20, blank=True)
avatar_url = models.URLField(max_length=255, blank=True)
status = models.SmallIntegerField(default=1)
extra_data = models.JSONField(default=dict, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'users'
verbose_name = '用户'
verbose_name_plural = '用户'
4.2 注册功能实现
注册功能看着简单,但坑不少。我建议分三步走:
- 前端校验 — 格式、长度、密码强度
- 后端校验 — 唯一性、合法性
- 业务处理 — 加密、入库、发激活邮件
为什么要有前端校验?你想想看,如果每次提交都等后端返回错误,用户体验得多差。但前端校验只是辅助,真正的安全防线在后端。
注意: 密码不能明文存储!我曾经接手过一个项目,用户表里存的都是明文密码,吓得我连夜改了。一定要用哈希算法,比如 bcrypt 或 Django 自带的 PBKDF2。
注册接口的核心逻辑:
from django.contrib.auth.hashers import make_password
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['POST'])
def register(request):
username = request.data.get('username')
password = request.data.get('password')
email = request.data.get('email')
# 校验用户名是否已存在
if User.objects.filter(username=username).exists():
return Response({'error': '用户名已被注册'}, status=400)
# 密码加密
password_hash = make_password(password)
# 创建用户
user = User.objects.create(
username=username,
password=password_hash,
email=email,
status=0 # 未激活
)
# 发送激活邮件(异步任务)
send_activation_email.delay(user.id)
return Response({'message': '注册成功,请查收激活邮件'}, status=201)
避坑指南: 我曾经把密码校验放在加密之后,结果校验逻辑全废了。记住,校验要在加密之前做。
4.3 登录与认证机制
登录认证这块,我推荐用 JWT(JSON Web )。为什么不用 Session?说白了,Session 在分布式环境下太麻烦了,你得搞 Redis 共享 Session,还得考虑粘性问题。JWT 无状态,后端只管签发和验证,省心不少。
JWT 的流程其实很简单:
登录接口实现:
import jwt
from django.contrib.auth.hashers import check_password
from datetime import datetime, timedelta
SECRET_KEY = 'your-secret-key-here'
@api_view(['POST'])
def login(request):
username = request.data.get('username')
password = request.data.get('password')
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return Response({'error': '用户不存在'}, status=401)
# 校验密码
if not check_password(password, user.password_hash):
return Response({'error': '密码错误'}, status=401)
# 检查状态
if user.status != 1:
return Response({'error': '账号未激活或已被禁用'}, status=403)
# 生成 JWT
payload = {
'user_id': user.id,
'username': user.username,
'exp': datetime.utcnow() + timedelta(days=7)
}
= jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return Response({
'': ,
'user': {
'id': user.id,
'username': user.username,
'email': user.email
}
})
关键点: JWT 的过期时间别设太长。我一般设 7 天,然后配合 refresh 做续期。这样就算 泄露,损失也能控制在 7 天内。
4.4 认证中间件
有了 JWT,还得有个中间件来验证每个请求。说白了,就是每次请求进来,先检查 是否有效。
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
class JWTAuthMiddleware(MiddlewareMixin):
def process_request(self, request):
# 白名单路径,不需要认证
whitelist = ['/api/register/', '/api/login/', '/api/docs/']
if request.path in whitelist:
return None
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
if not auth_header.startswith('Bearer '):
return JsonResponse({'error': '未提供认证信息'}, status=401)
= auth_header.split(' ')[1]
try:
payload = jwt.decode(, SECRET_KEY, algorithms=['HS256'])
request.user_id = payload['user_id']
request.username = payload['username']
except jwt.ExpiredSignatureError:
return JsonResponse({'error': ' 已过期'}, status=401)
except jwt.InvalidTokenError:
return JsonResponse({'error': '无效的 '}, status=401)
return None
我的经验: 白名单一定要维护好。我曾经忘了把重置密码接口加进去,结果用户连密码都改不了,被运营追着骂了一下午。
4.5 安全加固
最后聊几个安全细节:
- 密码强度 — 至少 8 位,包含大小写字母和数字
- 登录频率限制 — 同一 IP 5 分钟内最多尝试 10 次
- 刷新 — 提供 refresh 接口,避免用户频繁登录
- HTTPS — 这个不用我说了吧?明文传输密码等于裸奔
嗯,用户模块的核心内容就这些。下一章咱们开始搞商品模块,那才是电商系统的重头戏。