在django中-rest框架-simplejwt插件默认使用username和password。但是我想使用email而不是username。所以,我确实喜欢以下几点:
序列化程序中的:
class MyTokenObtainSerializer(Serializer):
username_field = User.EMAIL_FIELD
def __init__(self, *args, **kwargs):
super(MyTokenObtainSerializer, self).__init__(*args, **kwargs)
self.fields[self.username_field] = CharField()
self.fields['password'] = PasswordField()
def validate(self, attrs):
# self.user = authenticate(**{
# self.username_field: attrs[self.username_field],
# 'password': attrs['password'],
# })
self.user = User.objects.filter(email=attrs[self.username_field]).first()
print(self.user)
if not self.user:
raise ValidationError('The user is not valid.')
if self.user:
if not self.user.check_password(attrs['password']):
raise ValidationError('Incorrect credentials.')
print(self.user)
# Prior to Django 1.10, inactive users could be authenticated with the
# default `ModelBackend`. As of Django 1.10, the `ModelBackend`
# prevents inactive users from authenticating. App designers can still
# allow inactive users to authenticate by opting for the new
# `AllowAllUsersModelBackend`. However, we explicitly prevent inactive
# users from authenticating to enforce a reasonable policy and provide
# sensible backwards compatibility with older Django versions.
if self.user is None or not self.user.is_active:
raise ValidationError('No active account found with the given credentials')
return {}
@classmethod
def get_token(cls, user):
raise NotImplemented(
'Must implement `get_token` method for `MyTokenObtainSerializer` subclasses')
class MyTokenObtainPairSerializer(MyTokenObtainSerializer):
@classmethod
def get_token(cls, user):
return RefreshToken.for_user(user)
def validate(self, attrs):
data = super(MyTokenObtainPairSerializer, self).validate(attrs)
refresh = self.get_token(self.user)
data['refresh'] = text_type(refresh)
data['access'] = text_type(refresh.access_token)
return data视图:
class MyTokenObtainPairView(TokenObtainPairView):
"""
Takes a set of user credentials and returns an access and refresh JSON web
token pair to prove the authentication of those credentials.
"""
serializer_class = MyTokenObtainPairSerializer而且很管用!!
现在我的问题是,我怎样才能更有效地做到这一点?有人能对此提出建议吗?提前谢谢。
发布于 2019-08-19 11:52:33
这个答案是给未来读者的,因此包含了额外的信息。
为了简化身份验证后端,您需要连接多个类。我建议在下面执行选项1 (还有可选的选项3,您的简化版本)。在你读到之前,有几个笔记:
User.objects.filter(email__iexact=...)以不区分大小写的方式匹配电子邮件。get_user_model()来代替默认的用户模型,这确实是初学者的生命保护程序!至于三个备选方案:
class EmailModelBackend(ModelBackend)和替换身份验证函数。
authenticate(username=, password=, **kwarg)authenticate(...)调整其他应用程序,只替换JWT (如果设置为这样的话)参数是不需要的,因此这个选项不太建议使用)。
MyTokenObtainPairSerializer与电子邮件作为索赔。
选项1 (请注意,这也允许用户名!):
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
class EmailorUsernameModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None选项2:跳过,留给读者,不提建议。
选项3:,您似乎已经在上面讨论了这个问题。
注意:您不必定义MyTokenObtainPairView,您可以在urls.py中使用TokenObtainPairView(serializer_class=MyTokenObtainPairSerializer).as_view()。小的简化,它覆盖了使用的令牌序列化程序。
备注2:您可以指定标识声明和在settings.py (或设置文件)中添加的数据来使用电子邮件。这将使您的前端应用程序也使用电子邮件进行索赔(而不是默认的用户.id)。
SIMPLE_JWT = {
'USER_ID_FIELD': 'id', # model property to attempt claims for
'USER_ID_CLAIM': 'user_id', # actual keyword in token data
}但是,请注意创建者发出的唯一性警告:
例如,指定“用户名”或“电子邮件”字段将是一个糟糕的选择,因为帐户的用户名或电子邮件可能会根据给定服务中帐户管理的设计方式而改变。
如果你能保证唯一性,你就都准备好了。
发布于 2019-11-13 15:08:40
为什么你要复制和粘贴那么多而不是子类呢?我要处理的是:
# serializers.py
from rest_framework_simplejwt.serializers import TokenObtainSerializer
class EmailTokenObtainSerializer(TokenObtainSerializer):
username_field = User.EMAIL_FIELD
class CustomTokenObtainPairSerializer(EmailTokenObtainSerializer):
@classmethod
def get_token(cls, user):
return RefreshToken.for_user(user)
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data["refresh"] = str(refresh)
data["access"] = str(refresh.access_token)
return data和
# views.py
from rest_framework_simplejwt.views import TokenObtainPairView
class EmailTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer当然还有
#urls.py
from rest_framework_simplejwt.views import TokenRefreshView
from .views import EmailTokenObtainPairView
url("token/", EmailTokenObtainPairView.as_view(), name="token_obtain_pair"),
url("refresh/", TokenRefreshView.as_view(), name="token_refresh"),发布于 2020-09-16 16:39:42
这个问题已经有一段时间了,但是,我添加了+1作为@Mic的答案。顺便问一下,仅按以下方式更新到TokenObtainPairSerializer不就足够了吗?
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import (
TokenObtainPairSerializer, User
)
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
username_field = User.EMAIL_FIELD
class EmailTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializerhttps://stackoverflow.com/questions/54157056
复制相似问题