登录后刷新页面出现CSRF验证失败错误的问题求助
问题描述
成功登录后刷新页面,系统提示重新提交表单,点击继续后出现“CSRF verification failed. Request aborted.”错误。
已尝试方案
使用@csrf_exempt装饰器可解决问题,但因涉及登录表单,存在安全风险,故不考虑该方案。
相关代码
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login</title> </head> <body> Home {% if user.is_authenticated %} Hello {{name}} you are logged<br> <a href="{% url 'logout' %}">logout</a> {% else %} <form method="post"> {% csrf_token %} {{form.as_p}} <button type="submit">login</button> {% endif %} </form> </body> </html>
views.py
from django.shortcuts import render, redirect from login_app.forms import LoginForm, UserRegistrationForm from django.contrib.auth import authenticate, login, logout from django.middleware.csrf import get_token from django.http import HttpResponseForbidden # Create your views here. def home(request): form = LoginForm() return render(request,'home.html',{'form':form}) def log_in(request): if request.method == 'POST': form = LoginForm(request.POST) # if request.POST.get('csrfmiddlewaretoken') == get_token(request): # return HttpResponseForbidden('invalid') if form.is_valid(): email = form.cleaned_data['email'] password = form.cleaned_data['password'] try: user = authenticate(email = email,password=password) if user is None: raise ValueError('not found') print(login(request,user)) login(request,user) return render(request,'after.html',{'name':user}) # return redirect('home') except ValueError as e: return redirect('home') else: form = LoginForm() return redirect('home') def log_out(request): logout(request) return redirect('home')
models.py
from typing import Any from django.db import models from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager from django.contrib.auth import authenticate # Create your models here. class CustomUserManager(UserManager): def _create_user(self, email, password, **extra_fields): if not email: raise ValueError("Email can not be empty") email = self.normalize_email(email) user = self.model(email = email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_user(self, email=None, password=None, **extra_fields): extra_fields.setdefault('is_staff', False) extra_fields.setdefault('is_superuser', False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email=None, password=None, **extra_fields): extra_fields.setdefault('is_staff',True) extra_fields.setdefault('is_superuser', True) return self._create_user(email,password, **extra_fields) class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(blank=True, default='',unique=True) phone_number = models.CharField(max_length=12,unique=True,blank=True,default='') password = models.CharField(max_length=200) name= models.CharField(max_length=255,blank=True,default='') is_active = models.BooleanField(default=True) is_superuser = models.BooleanField(default=False) is_staff = models.BooleanField(default=False) date_joined = models.DateTimeField(auto_now_add=True) last_login = models.DateTimeField(blank=True, null=True) objects = CustomUserManager() USERNAME_FIELD = 'email' EMAIL_FIELD = 'email' REQUIRED_FIELDS = [] class Meta: verbose_name = 'Custom User' verbose_name_plural = 'Custom Users' def get_full_name(self): return self.name def get_short_name(self): return self.name or self.email.split('@')[0]
urls.py
from django.urls import path from login_app.views import home, log_in, log_out urlpatterns = [ path("",home,name='home'), path("log_in",log_in,name='log_in'), path("log_out",log_out,name='log_out'), ]
forms.py
from django import forms from login_app.models import User class LoginForm(forms.Form): email = forms.EmailField(label='Email',max_length=100) password = forms.CharField(label='Password',widget=forms.PasswordInput) class UserRegistrationForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput) class Meta: model = User fields = ['phone_number','email','name','password']
解决方案
问题核心是登录成功后直接用render返回页面,浏览器会保留POST请求上下文,刷新时会重新提交已失效的POST请求,导致CSRF验证失败。需遵循**Post/Redirect/Get (PRG)**模式,登录成功后重定向到GET请求页面。
1. 修改views.py中的log_in函数
def log_in(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): email = form.cleaned_data['email'] password = form.cleaned_data['password'] user = authenticate(email=email, password=password) if user is not None: login(request, user) # 替换原render为redirect,跳转到登录后的页面 return redirect('home') # 验证失败返回登录页并提示错误 return render(request, 'home.html', {'form': form, 'error': 'Invalid email or password'}) else: form = LoginForm() return render(request, 'home.html', {'form': form})
2. 调整模板展示错误提示(以home.html为例)
在模板中添加错误提示代码,方便用户看到登录失败原因:
{% if error %} <p style="color:red;">{{ error }}</p> {% endif %}
3. 额外检查项
- 确保
settings.py中启用django.middleware.csrf.CsrfViewMiddleware中间件(默认已启用) - 确认登录表单中
{% csrf_token %}标签位置正确(代码中已正确添加) - 验证自定义用户模型的
authenticate方法逻辑正常,确保用户登录后会话正确建立
内容的提问来源于stack exchange,提问作者Smith
相关产品推荐
相关产品推荐

