You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django REST API实现员工邮箱+密码JWT登录功能

实现基于Personal_email和密码的JWT登录方案

要实现JWT登录,核心是搞定密码的哈希存储和验证逻辑,Django自带的密码工具已经很成熟,给你两种可行方案,按需选择:

方案1:直接扩展Employee模型(适合不需要Django内置用户权限的场景)

1. 修正并更新Employee模型

给Employee添加密码字段,同时处理密码哈希避免明文存储,还要修正原代码里的语法错误(比如字段类首字母需大写、必填参数不能缺):

from django.db import models
from django.contrib.auth.hashers import make_password, check_password

class Employee(models.Model):
    Fname = models.CharField(max_length=50)
    Lname = models.CharField(max_length=50)
    Personal_email = models.EmailField(unique=True)  # 设为唯一,防止重复注册
    Department = models.CharField(choices=[('HR', '人力资源'), ('DEV', '开发部')], max_length=10)  # 补全ChoiceField的选项参数
    Designation = models.CharField(max_length=50)
    password = models.CharField(max_length=128)  # 存储哈希后的密码,128位长度足够

    def save(self, *args, **kwargs):
        # 保存时自动哈希密码,已哈希过的内容不再重复处理
        if self.password and not self.password.startswith('pbkdf2_sha256$'):
            self.password = make_password(self.password)
        super().save(*args, **kwargs)

    def check_password(self, raw_password):
        # 自定义密码验证方法
        return check_password(raw_password, self.password)

注意:原代码里的charfield()、Emailfield都是小写错误,Django模型字段类首字母必须大写,比如CharField、EmailField,别忘了修正。

2. 调整序列化器

注册时让密码仅作为输入字段,返回结果中不暴露:

from rest_framework import serializers
from .models import Employee

class EmployeeCreateSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)  # 只写字段,序列化返回时自动排除

    class Meta:
        model = Employee
        fields = ['Fname', 'Lname', 'Personal_email', 'Department', 'Designation', 'password']

class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        exclude = ['password']  # 显式排除密码字段

原代码里Modelserializer少了大写的M,fields = '__all__缺了闭合引号,这些语法错误必须修正,否则无法运行。

3. 实现JWT登录(用主流的simplejwt库)

先安装依赖:

pip install djangorestframework-simplejwt

然后在settings.py中配置:

INSTALLED_APPS = [
    # ...你的其他应用
    'rest_framework',
    'rest_framework_simplejwt',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

# 可选:配置令牌有效期
from datetime import timedelta
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}

接下来写自定义登录视图,验证邮箱和密码:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken
from .models import Employee
from .serializers import EmployeeSerializer

class EmployeeLoginView(APIView):
    def post(self, request):
        email = request.data.get('Personal_email')
        password = request.data.get('password')

        if not email or not password:
            return Response({'error': '请填全邮箱和密码'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            employee = Employee.objects.get(Personal_email=email)
        except Employee.DoesNotExist:
            return Response({'error': '该邮箱未注册'}, status=status.HTTP_401_UNAUTHORIZED)

        if employee.check_password(password):
            # 生成JWT令牌
            refresh = RefreshToken.for_user(employee)
            return Response({
                'refresh': str(refresh),
                'access': str(refresh.access_token),
                'employee': EmployeeSerializer(employee).data
            })
        else:
            return Response({'error': '密码错误'}, status=status.HTTP_401_UNAUTHORIZED)

要是想更规范,让Employee继承Django的AbstractBaseUser和PermissionsMixin,这样就能直接用simplejwt的默认视图,不用自己写登录逻辑。修改后的模型如下:

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

class EmployeeManager(BaseUserManager):
    def create_user(self, personal_email, password=None, **extra_fields):
        if not personal_email:
            raise ValueError('必须提供个人邮箱')
        email = self.normalize_email(personal_email)
        user = self.model(Personal_email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

class Employee(AbstractBaseUser, PermissionsMixin):
    Fname = models.CharField(max_length=50)
    Lname = models.CharField(max_length=50)
    Personal_email = models.EmailField(unique=True)
    Department = models.CharField(choices=[('HR', '人力资源'), ('DEV', '开发部')], max_length=10)
    Designation = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = EmployeeManager()

    USERNAME_FIELD = 'Personal_email'  # 指定用邮箱作为登录标识
    REQUIRED_FIELDS = ['Fname', 'Lname']

    def __str__(self):
        return self.Personal_email

这种情况下,直接用simplejwt的默认路由即可,无需自定义登录视图:

from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    # ...其他路由
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

登录时向/api/token/发送POST请求,传递username(即Personal_email)和password参数即可。


方案2:关联Django内置User模型(适合需要用到权限、组等Django用户功能的场景)

1. 修改模型,添加一对一关联

from django.db import models
from django.contrib.auth.models import User

class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee')
    Fname = models.CharField(max_length=50)
    Lname = models.CharField(max_length=50)
    Personal_email = models.EmailField(unique=True)
    Department = models.CharField(choices=[('HR', '人力资源'), ('DEV', '开发部')], max_length=10)
    Designation = models.CharField(max_length=50)

2. 更新注册视图,同时创建User和Employee

注册时先创建User对象,再绑定对应的Employee信息:

from rest_framework import generics
from rest_framework.response import Response
from django.contrib.auth.models import User
from .models import Employee
from .serializers import EmployeeCreateSerializer

class RegisterEmployeeView(generics.CreateAPIView):
    serializer_class = EmployeeCreateSerializer

    def post(self, request):
        # 先创建User,用邮箱作为用户名
        user = User.objects.create_user(
            username=request.data['Personal_email'],
            email=request.data['Personal_email'],
            password=request.data['password']
        )
        # 再创建Employee,关联刚创建的User
        employee_data = {
            'user': user.id,
            'Fname': request.data['Fname'],
            'Lname': request.data['Lname'],
            'Personal_email': request.data['Personal_email'],
            'Department': request.data['Department'],
            'Designation': request.data['Designation']
        }
        serializer = self.get_serializer(data=employee_data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({
            "employee": serializer.data,
            "message": "员工注册成功..!",
        })

3. JWT登录配置

同样使用simplejwt的默认视图,登录时传递username(即Personal_email)和password即可。后续需要获取员工信息时,直接通过request.user.employee就能拿到关联的Employee对象。


路由配置示例

from django.urls import path
from .views import RegisterEmployeeView, EmployeeLoginView
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    path('register/', RegisterEmployeeView.as_view(), name='register-employee'),
    # 方案1自定义登录视图用这条
    path('login/', EmployeeLoginView.as_view(), name='login-employee'),
    # 方案2或方案1继承AbstractBaseUser时用以下路由
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

内容的提问来源于stack exchange,提问作者orange freeze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:01:19