如何在Django中检测用户是否曾完成过身份验证?
Got it, let's work through this problem step by step. You want to check if a Django user has ever authenticated—returning true if they're currently logged in or have logged in before (even if they're logged out now), and only false if they've never logged in at all. You mentioned not wanting to use cookies, so I'll start with a server-side approach first, then cover the cookie method just in case you need it.
This approach uses Django's built-in session system and a custom user field to keep track of authentication history securely on the server.
Step 1: Add a Tracking Field to Your User Model
First, we need a way to store whether a user has ever logged in. If you're using a custom user model (highly recommended for Django projects), add a boolean field:
# models.py in your app from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): has_ever_logged_in = models.BooleanField(default=False)
Don't forget to update your settings.py to use this custom user model:
# settings.py AUTH_USER_MODEL = "your_app_name.CustomUser"
Then run migrations to apply the change:
python manage.py makemigrations python manage.py migrate
If you're stuck using Django's default User model, create a Profile model with a one-to-one relationship to User instead:
# models.py from django.contrib.auth.models import User from django.db import models class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) has_ever_logged_in = models.BooleanField(default=False)
Step 2: Update the Field on First Login
Use Django's user_logged_in signal to set the has_ever_logged_in field when a user logs in for the first time. We'll also set a session flag so we can track logged-out users who were previously authenticated.
Create a signals.py file in your app:
# signals.py from django.contrib.auth.signals import user_logged_in from django.dispatch import receiver from .models import CustomUser # Or UserProfile if using default User @receiver(user_logged_in) def handle_first_login(sender, user, request, **kwargs): # Update the user model field if not user.has_ever_logged_in: user.has_ever_logged_in = True user.save() # Set a session flag to track logged-out users request.session['has_ever_authenticated'] = True
Register the signal in your app's apps.py so Django picks it up:
# 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
Step 3: Check the Authentication History
Now you can write a helper function to check the status anywhere in your code:
def has_ever_authenticated(request): # Return true if user is currently logged in if request.user.is_authenticated: return True # Return true if session has the flag (user was logged in before) return request.session.get('has_ever_authenticated', False)
In templates, you can check it like this:
{% if user.is_authenticated or request.session.has_ever_authenticated %} <!-- User has authenticated before (or is logged in) --> {% else %} <!-- User has never authenticated --> {% endif %}
Caveat
If a user clears their browser cookies, the session ID is lost, so the session flag will disappear. But if they log in again, the has_ever_logged_in field will still be true, so we'll catch it then.
If you decide to use cookies despite your initial hesitation, here's a secure way to implement it:
Step 1: Set a Persistent Cookie on First Login
Override Django's default login view to set a cookie when the user logs in for the first time:
# views.py from django.contrib.auth.views import LoginView class CustomLoginView(LoginView): def form_valid(self, form): response = super().form_valid(form) # Only set the cookie if it doesn't exist already if not self.request.COOKIES.get('has_ever_authenticated'): response.set_cookie( 'has_ever_authenticated', 'true', max_age=365 * 24 * 60 * 60, # Expire in 1 year httponly=True, # Prevent JS access to mitigate XSS secure=self.request.is_secure() # Use secure cookie if using HTTPS ) return response
Update your urls.py to use this custom login view instead of the default:
# urls.py from django.urls import path from .views import CustomLoginView urlpatterns = [ path('login/', CustomLoginView.as_view(), name='login'), # Other URLs... ]
Step 2: Check the Cookie
Use this helper function to check the cookie status:
def has_ever_authenticated(request): if request.user.is_authenticated: return True return request.COOKIES.get('has_ever_authenticated') == 'true'
In templates:
{% if user.is_authenticated or request.COOKIES.has_ever_authenticated == 'true' %} <!-- User has authenticated before --> {% else %} <!-- User has never authenticated --> {% endif %}
Caveat
Users can manually delete cookies, which would reset this status. This is less secure than the server-side approach, but it works if you need to track users who clear their sessions but not their cookies.
内容的提问来源于stack exchange,提问作者crimsonpython24

