使用Django rest-auth与allauth时,未验证邮箱仍允许登录的问题
解决Django rest-auth + allauth 需邮箱验证后才能登录激活的问题
哈,这个场景我之前踩过坑,刚好能给你一步步捋清楚怎么配置:
1. 先把注册后的用户默认设为非活跃状态
rest-auth默认注册完就把is_active设为True了,咱们得自定义注册序列化器来改掉这个行为:
# 在你的app下新建/修改serializers.py from rest_auth.registration.serializers import RegisterSerializer from django.contrib.auth import get_user_model User = get_user_model() class CustomRegisterSerializer(RegisterSerializer): def save(self, request): # 先调用父类的save方法创建用户 user = super().save(request) # 把用户设为非活跃 user.is_active = False user.save() return user
然后在settings.py里指定用这个自定义序列化器:
REST_AUTH_REGISTER_SERIALIZERS = { 'REGISTER_SERIALIZER': 'your_app_name.serializers.CustomRegisterSerializer', }
2. 让邮箱验证后自动激活用户
现在注册后的用户是is_active=False,接下来要实现:用户点击验证链接后,自动把is_active改成True。这里有两种常用方法:
方法一:用信号监听邮箱验证事件
这是最简洁的方式,在你的app下新建signals.py:
from django.db.models.signals import post_save from django.dispatch import receiver from allauth.account.models import EmailAddress from django.contrib.auth import get_user_model User = get_user_model() @receiver(post_save, sender=EmailAddress) def activate_user_after_email_verify(sender, instance, **kwargs): # 当邮箱被标记为已验证,且用户还没激活时,激活用户 if instance.verified and not instance.user.is_active: instance.user.is_active = True instance.user.save()
然后要在app的apps.py里注册这个信号,确保项目启动时加载:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app_name' def ready(self): import your_app_name.signals
方法二:重写邮箱验证视图
如果信号的方式不满足你的定制需求,可以重写allauth的验证视图:
# views.py from allauth.account.views import ConfirmEmailView from django.contrib.auth import get_user_model User = get_user_model() class CustomConfirmEmailView(ConfirmEmailView): def post(self, *args, **kwargs): # 先执行父类的验证逻辑 response = super().post(*args, **kwargs) # 获取当前验证邮箱对应的用户 user = self.object.email_address.user # 激活用户 if not user.is_active: user.is_active = True user.save() return response
然后在项目的urls.py里替换默认的验证路由:
from django.urls import path, include from your_app_name.views import CustomConfirmEmailView urlpatterns = [ # ... 其他路由 # 替换allauth的默认邮箱验证路由 path('accounts/confirm-email/<str:key>/', CustomConfirmEmailView.as_view(), name='account_confirm_email'), path('rest-auth/', include('rest_auth.urls')), path('rest-auth/registration/', include('rest_auth.registration.urls')), ]
3. 可选:登录时强制检查邮箱是否验证
即使用户被激活了,也可以再加一层保障:登录时必须确保邮箱已验证。自定义登录序列化器:
# serializers.py from rest_auth.serializers import LoginSerializer from allauth.account.models import EmailAddress from rest_framework import serializers class CustomLoginSerializer(LoginSerializer): def validate(self, attrs): # 先调用父类的验证逻辑,拿到用户对象 user = super().validate(attrs) # 检查该用户是否有已验证的邮箱 has_verified_email = EmailAddress.objects.filter(user=user, verified=True).exists() if not has_verified_email: raise serializers.ValidationError("请先验证你的邮箱后再登录") return user
在settings.py里配置使用这个登录序列化器:
REST_AUTH_SERIALIZERS = { 'LOGIN_SERIALIZER': 'your_app_name.serializers.CustomLoginSerializer', }
4. 基础配置检查
最后别忘了确保settings.py里的allauth核心配置是正确的:
# 强制要求注册时提供邮箱 ACCOUNT_EMAIL_REQUIRED = True # 强制邮箱验证,注册后自动发送验证邮件 ACCOUNT_EMAIL_VERIFICATION = "mandatory" # 可选:设置用邮箱作为登录凭证(比用户名更合理) ACCOUNT_AUTHENTICATION_METHOD = "email" ACCOUNT_UNIQUE_EMAIL = True
这样一套配置下来,用户注册后is_active为False,必须点击邮件链接验证邮箱后,is_active才会被设为True,而且登录时也会检查邮箱是否验证,完全符合你的需求啦~
内容的提问来源于stack exchange,提问作者Bleh
相关产品推荐
相关产品推荐

