DRF:不使用 USERNAME_FIELD 进行身份验证
Drf: authenticating without the USERNAME_FIELD
扩展自:
我试图弄清楚如何使用未设置为 USERNAME_FIELD 的字段对用户进行身份验证并遇到了一些问题,它让我输入了正确的数据字段,但它从不进行身份验证
我正在使用之前问题答案中的这个片段:
class MyTokenStudentSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['student_id'] = serializers.CharField(required=False)
# self.fields['password'] = serializers.CharField(write_only=True, required=True)
self.fields['password'] = PasswordField(trim_whitespace=False)
username_field = 'student_id'
auth_fields = ['student_id']
#login view extended from TokenObtainPairView
class LoginStudentView(TokenObtainPairView):
permission_classes = (AllowAny,)
serializer_class = MyTokenStudentSerializer
生产
{
"detail": "No active account found with the given credentials"
}
如有任何修改,我们将不胜感激。
如果您使用默认 ModelBackend you should specify USERNAME_FIELD
class User(AbstractUser):
USERNAME_FIELD = 'student_id'
student_id = models.TextField(default="", unique=True) # Should be unique
输出
~ $ curl -X POST "http://127.0.0.1:8000/api/auth/login-student/" -d "password=admin&student_id=stdnt"
{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY0MzcxMTgzMCwiaWF0IjoxNjQxMTE5ODMwLCJqdGkiOiJkY2MyNTEwZGRiNWE0ZTJmODllMDI2OWRkYWI5ZGVjNSIsInVzZXJfaWQiOjF9.c0QTdBhiPUf4yvPP0l3a-XQ0iD6kycECAdb6MAROY8g","access":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjQxMTIzNDMwLCJpYXQiOjE2NDExMTk4MzAsImp0aSI6ImM0NjA0ZTlhMDBhNjQ5YjdhMTkxOGQ3OTJmOTMyYTJiIiwidXNlcl9pZCI6MX0.XoZXTJICE_PyZFXIIvsm3bci-e-O67AsYvIvY1ijNAo"}
此外,您可以编写自己的身份验证后端并将其包含在 settings.py
中。
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'project.apps.auth.backends.MyCustomModelBackend',
]
后端示例
class MyCustomModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
student_id = kwargs.get("student_id")
if student_id is None or password is None:
return
try:
user = User.objects.get(student_id=student_id)
except User.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
使用这种方法,您可以通过 username
字段保留登录信息。此外,您不应在 User
模型
中指定 USERNAME_FIELD = 'student_id'
扩展自:
我试图弄清楚如何使用未设置为 USERNAME_FIELD 的字段对用户进行身份验证并遇到了一些问题,它让我输入了正确的数据字段,但它从不进行身份验证
我正在使用之前问题答案中的这个片段:
class MyTokenStudentSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['student_id'] = serializers.CharField(required=False)
# self.fields['password'] = serializers.CharField(write_only=True, required=True)
self.fields['password'] = PasswordField(trim_whitespace=False)
username_field = 'student_id'
auth_fields = ['student_id']
#login view extended from TokenObtainPairView
class LoginStudentView(TokenObtainPairView):
permission_classes = (AllowAny,)
serializer_class = MyTokenStudentSerializer
生产
{
"detail": "No active account found with the given credentials"
}
如有任何修改,我们将不胜感激。
如果您使用默认 ModelBackend you should specify USERNAME_FIELD
class User(AbstractUser):
USERNAME_FIELD = 'student_id'
student_id = models.TextField(default="", unique=True) # Should be unique
输出
~ $ curl -X POST "http://127.0.0.1:8000/api/auth/login-student/" -d "password=admin&student_id=stdnt"
{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY0MzcxMTgzMCwiaWF0IjoxNjQxMTE5ODMwLCJqdGkiOiJkY2MyNTEwZGRiNWE0ZTJmODllMDI2OWRkYWI5ZGVjNSIsInVzZXJfaWQiOjF9.c0QTdBhiPUf4yvPP0l3a-XQ0iD6kycECAdb6MAROY8g","access":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjQxMTIzNDMwLCJpYXQiOjE2NDExMTk4MzAsImp0aSI6ImM0NjA0ZTlhMDBhNjQ5YjdhMTkxOGQ3OTJmOTMyYTJiIiwidXNlcl9pZCI6MX0.XoZXTJICE_PyZFXIIvsm3bci-e-O67AsYvIvY1ijNAo"}
此外,您可以编写自己的身份验证后端并将其包含在 settings.py
中。
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'project.apps.auth.backends.MyCustomModelBackend',
]
后端示例
class MyCustomModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
student_id = kwargs.get("student_id")
if student_id is None or password is None:
return
try:
user = User.objects.get(student_id=student_id)
except User.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
使用这种方法,您可以通过 username
字段保留登录信息。此外,您不应在 User
模型
USERNAME_FIELD = 'student_id'