4、用户模块设计:用户模型设计、注册功能实现、登录与认证机制

用户模块,说白了就是整个电商系统的「大门」。

我做了这么多年项目,见过太多团队一上来就写业务代码,结果用户注册登录这块漏洞百出。嗯,今天咱们就把这扇门给砌结实了。

4.1 用户模型设计

先聊聊模型设计。我个人习惯,用户表一定要预留扩展字段,别等上线了再改表结构,那滋味可不好受。

一个电商系统的用户模型,核心字段大概这些:

字段名 类型 说明
id BigInteger 主键,自增
username VARCHAR(50) 用户名,唯一索引
password_hash VARCHAR(128) 加密后的密码
email 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 注册功能实现

注册功能看着简单,但坑不少。我建议分三步走:

  1. 前端校验 — 格式、长度、密码强度
  2. 后端校验 — 唯一性、合法性
  3. 业务处理 — 加密、入库、发激活邮件

为什么要有前端校验?你想想看,如果每次提交都等后端返回错误,用户体验得多差。但前端校验只是辅助,真正的安全防线在后端。

注意: 密码不能明文存储!我曾经接手过一个项目,用户表里存的都是明文密码,吓得我连夜改了。一定要用哈希算法,比如 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 的流程其实很简单:

客户端 服务器 数据库 1. 用户名+密码 2. 查询用户 3. 返回用户信息 4. 返回 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 — 这个不用我说了吧?明文传输密码等于裸奔

嗯,用户模块的核心内容就这些。下一章咱们开始搞商品模块,那才是电商系统的重头戏。