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

基于Django Rest Framework、Serializers与Vue.js的重置密码功能实现咨询

DRF + Vue 无HTML视图的密码重置功能实现方案

整体流程概览

  • 用户在前端提交绑定邮箱发起重置请求
  • 后端校验账号存在后生成带时效的签名token,拼接前端重置页链接发送邮件
  • 用户点击邮件链接跳转到Vue的ResetPassword页,携带token参数
  • 用户提交新密码后前端携带token+新密码调用后端接口完成重置,跳转登录页

后端DRF实现部分

1. 依赖准备

直接使用Django自带的签名模块即可,无需额外安装第三方包:
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired

2. 密码重置请求接口(触发邮件发送)

  • 序列化器:仅校验邮箱格式、对应账号是否存在
from rest_framework import serializers
from django.contrib.auth import get_user_model
User = get_user_model()

class PasswordResetRequestSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    def validate_email(self, value):
        if not User.objects.filter(email=value).exists():
            raise serializers.ValidationError("该邮箱未绑定账号")
        return value
  • 视图逻辑:校验通过后生成签名token,拼接前端链接发邮件
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.core.mail import send_mail
from django.conf import settings

class PasswordResetRequestView(APIView):
    authentication_classes = []
    permission_classes = []
    def post(self, request):
        ser = PasswordResetRequestSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        email = ser.validated_data['email']
        user = User.objects.get(email=email)
        # 生成带时效的签名,加入用户id和密码修改时间戳,保证改密后旧token自动失效
        signer = TimestampSigner()
        token = signer.sign(f"{user.id}_{user.password_last_changed.timestamp()}")
        # 拼接前端重置页链接,FRONTEND_DOMAIN为你前端项目的部署域名,在settings里提前配置
        reset_link = f"{settings.FRONTEND_DOMAIN}/reset-password?token={token}"
        # 发邮件,内容可自定义
        send_mail(
            subject="密码重置通知",
            message=f"请点击链接重置密码,15分钟内有效:{reset_link}",
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[email],
            fail_silently=False
        )
        return Response({"msg": "重置邮件已发送,请查收"}, status=status.HTTP_200_OK)

3. 密码重置确认接口(提交新密码)

  • 序列化器:校验token有效性、新密码合法性、两次密码一致性
class PasswordResetConfirmSerializer(serializers.Serializer):
    token = serializers.CharField(required=True)
    new_password = serializers.CharField(required=True, min_length=8)
    confirm_password = serializers.CharField(required=True, min_length=8)
    def validate(self, attrs):
        if attrs['new_password'] != attrs['confirm_password']:
            raise serializers.ValidationError("两次输入密码不一致")
        # 校验token有效性和过期时间
        signer = TimestampSigner()
        try:
            # 15分钟有效期
            raw_value = signer.unsign(attrs['token'], max_age=15*60)
            user_id, pwd_change_ts = raw_value.split('_', 1)
            user = User.objects.get(id=user_id)
            if str(user.password_last_changed.timestamp()) != pwd_change_ts:
                raise serializers.ValidationError("token已失效")
            attrs['user'] = user
        except (BadSignature, SignatureExpired, User.DoesNotExist):
            raise serializers.ValidationError("token无效或已过期")
        return attrs
  • 视图逻辑:校验通过后修改密码
class PasswordResetConfirmView(APIView):
    authentication_classes = []
    permission_classes = []
    def post(self, request):
        ser = PasswordResetConfirmSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        user = ser.validated_data['user']
        user.set_password(ser.validated_data['new_password'])
        user.save()
        return Response({"msg": "密码重置成功"}, status=status.HTTP_200_OK)

4. 路由配置

from django.urls import path
urlpatterns = [
    # 你已有的用户创建接口
    path('users/', ...),
    # 新增重置密码接口
    path('password-reset/request/', PasswordResetRequestView.as_view()),
    path('password-reset/confirm/', PasswordResetConfirmView.as_view()),
]

前端Vue实现部分

1. 路由配置

新增重置密码页路由:

// router/index.js
const routes = [
    // 已有路由
    { path: '/login', component: () => import('@/views/Login.vue') },
    // 新增重置密码路由
    { path: '/reset-password', component: () => import('@/views/ResetPassword.vue') }
]

2. ResetPassword.vue核心逻辑

<template>
  <div class="reset-password">
    <div v-if="!tokenValid">链接无效或已过期,请重新发起重置请求</div>
    <div v-else>
      <input type="password" v-model="newPwd" placeholder="请输入新密码" />
      <input type="password" v-model="confirmPwd" placeholder="请确认新密码" />
      <button @click="handleSubmit">提交</button>
    </div>
  </div>
</template>
<script>
import axios from 'axios'
export default {
  data() {
    return {
      token: '',
      tokenValid: false,
      newPwd: '',
      confirmPwd: ''
    }
  },
  mounted() {
    // 获取url中的token参数
    this.token = this.$route.query.token
    this.tokenValid = !!this.token
  },
  methods: {
    async handleSubmit() {
      if (this.newPwd !== this.confirmPwd) {
        alert('两次输入密码不一致')
        return
      }
      try {
        await axios.post('/api/v1/password-reset/confirm/', {
          token: this.token,
          new_password: this.newPwd,
          confirm_password: this.confirmPwd
        })
        alert('密码重置成功,请重新登录')
        this.$router.push('/login')
      } catch (err) {
        alert(err.response.data.msg || '重置失败,请重试')
      }
    }
  }
}
</script>

注意事项

  • 提前配置好Django的邮件发送参数,测试邮件发送正常
  • 接口添加限流规则,避免被恶意调用刷邮件
  • 生产环境建议将密码复杂度校验逻辑加入序列化器,避免弱密码
  • 签名有效期建议设置为10~15分钟,降低泄露风险

内容的提问来源于stack exchange,提问作者Ivan Stepanchuk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 09:51:00