在已实现JWT视图的Django中如何创建用户注册登录表单?
在Django中实现JWT认证后,如何创建用户输入凭证的表单?
我正在学习用Django结合pyJWT实现用户身份验证,已经通过Postman测试完成了核心功能——用MySQL存储数据,密码哈希处理、Token生成都正常。现在卡在创建用户输入凭证的表单这一步,不知道怎么推进。
以下是现有代码:
Views.py
class RegisterView(APIView): def post(self, request): serializer = UserSerializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) class LoginView(APIView): def post(self, request): email = request.data['email'] password = request.data['password'] user = User.objects.filter(email=email).first() if user is None: raise AuthenticationFailed('User not found') if not user.check_password(password): raise AuthenticationFailed('Incorrect password') payload = { 'id': user.id, 'exp': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=60), 'iat': datetime.datetime.now(datetime.timezone.utc) } token = jwt.encode(payload, 'secret', algorithm='HS256') response = Response() response.set_cookie(key='jwt', value=token, httponly=True) response.data = {"jwt": token} return response class UserView(APIView): def get(self, request): token = request.COOKIES.get('jwt') if not token: raise AuthenticationFailed('Unathenticated!') try: payload = jwt.decode(token, 'secret', algorithms=['HS256']) except jwt.ExpiredSignatureError: raise AuthenticationFailed('Uathenticated') user = User.objects.filter(id=payload['id']).first() serializer = UserSerializer(user) return Response(serializer.data) class LogoutView(APIView): def post(self, request): response = Response() response.delete_cookie('jwt') response.data = {'message': 'Success'} return response
Serializers.py
class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'email', 'password', 'first_name', 'last_name', 'username'] extra_kwargs = {"password": {"write_only": True}} def create(self, validated_data): password = validated_data.pop('password', None) instance = self.Meta.model(**validated_data) if password is not None: instance.set_password(password) instance.save() return instance
Models.py
class User(AbstractUser): email = models.CharField(max_length=255, unique=True) password = models.CharField(max_length=255) first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) username = models.CharField(max_length=255) USERNAME_FIELD = 'email' REQUIRED_FIELDS = []
解决方案:两种表单实现方式
方式1:Django原生服务端渲染表单
适合传统服务端渲染的场景,复用现有业务逻辑:
- 创建表单文件
forms.py
from django import forms from .models import User class RegisterForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput) confirm_password = forms.CharField(widget=forms.PasswordInput) class Meta: model = User fields = ['email', 'username', 'first_name', 'last_name', 'password'] def clean(self): cleaned_data = super().clean() password = cleaned_data.get('password') confirm_password = cleaned_data.get('confirm_password') if password != confirm_password: raise forms.ValidationError("密码不匹配") return cleaned_data class LoginForm(forms.Form): email = forms.EmailField() password = forms.CharField(widget=forms.PasswordInput)
- 添加表单处理视图
在views.py中新增处理页面渲染和表单提交的视图:
from django.shortcuts import render, redirect from .forms import RegisterForm, LoginForm # 注册页面 def register_page(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): # 复用现有Serializer逻辑创建用户 serializer = UserSerializer(data=form.cleaned_data) serializer.is_valid(raise_exception=True) serializer.save() return redirect('login_page') else: form = RegisterForm() return render(request, 'register.html', {'form': form}) # 登录页面 def login_page(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): email = form.cleaned_data['email'] password = form.cleaned_data['password'] # 复用现有LoginView的验证逻辑 user = User.objects.filter(email=email).first() if user and user.check_password(password): payload = { 'id': user.id, 'exp': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=60), 'iat': datetime.datetime.now(datetime.timezone.utc) } token = jwt.encode(payload, 'secret', algorithm='HS256') response = redirect('user_profile') response.set_cookie(key='jwt', value=token, httponly=True) return response else: form.add_error(None, '邮箱或密码错误') else: form = LoginForm() return render(request, 'login.html', {'form': form})
- 创建模板文件
在templates目录下创建register.html和login.html:register.html示例:
<!DOCTYPE html> <html> <head> <title>用户注册</title> </head> <body> <h2>注册账号</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">完成注册</button> </form> </body> </html>
方式2:前后端分离的前端表单
如果是前后端分离架构,直接通过AJAX调用已有的API接口:
<!DOCTYPE html> <html> <head> <title>用户登录</title> </head> <body> <h2>登录</h2> <form id="loginForm"> <div> <label>邮箱:</label> <input type="email" name="email" required> </div> <div> <label>密码:</label> <input type="password" name="password" required> </div> <button type="submit">登录</button> </form> <script> document.getElementById('loginForm').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const data = Object.fromEntries(formData); try { const response = await fetch('/api/login/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data), credentials: 'include' // 携带Cookie保存Token }); const result = await response.json(); if (response.ok) { alert('登录成功'); window.location.href = '/api/user/'; } else { alert(result.detail || '登录失败'); } } catch (err) { alert('请求出错,请稍后重试'); } }); </script> </body> </html>
注册表单逻辑类似,只需将请求地址改为/api/register/即可。
内容的提问来源于stack exchange,提问作者mdm1e
相关产品推荐
相关产品推荐

