使用 Django REST Framework 更新 USERNAME_FIELD 时如何处理令牌
How to handle token when UPDATE USERNAME_FIELD with Django REST Framework
我正在使用 Django REST Framework 和 Angular 4.
开发应用程序
我不知道更新登录用户信息时令牌的处理方式。
Django的用户模型定制如下
登录密钥从用户名更改为电子邮件。
[models.py]
class Account(AbstractBaseUser):
username = models.CharField(_('username'), max_length=30, unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
profile = models.CharField(_('profile'), max_length=255, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def user_has_perm(user, perm, obj):
return _user_has_perm(user, perm, obj)
def has_perm(self, perm, obj=None):
return _user_has_perm(self, perm, obj=obj)
def has_module_perms(self, app_label):
return self.is_admin
def get_short_name(self):
return self.first_name
@property
def is_superuser(self):
return self.is_admin
class Meta:
db_table = 'api_user'
swappable = 'AUTH_USER_MODEL'
Angular4更新用户信息的函数实现如下
使用函数 updateUserInfo 将新用户信息放入 Django REST Framework 中。
[component.ts]
updateUserInfo() {
this.authService.updateUserInfo({
email: this.editUserEmail,
username: this.editUserName,
profile: this.edtiUserProfile
})
.subscribe(
data => {
this.updateSuccessMessage = "success userinfo update";
this.updateErrorMessage = null;
this.authService.userInfo;
},
error => {
this.updateErrorMessage = "failed userinfo update";
this.updateSuccessMessage = null;
}
);
}
[service.ts]
updateUserInfo(userUpdateInfo) {
return this.http
.put(this.UpdateUserUrl,
userUpdateInfo,
this.jwt()
);
}
jwt() {
if (this.LoginToken) {
let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'JWT ' + this.LoginToken.token });
return new RequestOptions({ headers: headers });
}
}
Django中更新用户信息的视图和序列化器如下
[views.py]
class AuthInfoUpdateView(generics.UpdateAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = AccountSerializer
lookup_field = 'email'
queryset = Account.objects.all()
def get_object(self):
try:
instance = self.queryset.get(email=self.request.user)
return instance
except Account.DoesNotExist:
raise Http404
[serializers.py]
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'username', 'email', 'profile', 'password')
def create(self, validated_data):
return Account.objects.create_user(request_data=validated_data)
def update(self, instance, validated_data):
if 'password' in validated_data:
instance.set_password(validated_data['password'])
else:
instance = super().update(instance, validated_data)
instance.save()
return instance
现在发生的问题是更新电子邮件时的行为。
因为USERNAME_FIELD是邮件,更新邮件就得更新前端持有的token。
但是我不知道如何用新邮件获取token。
我认为保持用户身份验证的唯一方法是生成一个新令牌并将其发回,我不知道使用 django-rest-framework-jwt 执行此操作的另一种方法。
为此,您需要自定义 AuthInfoUpdateView
的 put
方法:
def put(self, request, *args, **kwargs):
serializer = self.serializer_class(self.get_object(), data=request.data, partial=True)
if serializer.is_valid():
instance = serializer.save()
# Generate a new token
payload = jwt_payload_handler(instance)
token = jwt.encode(payload, settings.SECRET_KEY)
response = JsonResponse({'token': token.decode('unicode_escape')})
response.status = 200
return response
else:
response = JsonResponse({'errors': serializer.errors})
response.status = 500
return response
就这么简单,您只需在前端更新令牌,而无需提示用户再次登录。
希望对您有所帮助!
我正在使用 Django REST Framework 和 Angular 4.
开发应用程序
我不知道更新登录用户信息时令牌的处理方式。
Django的用户模型定制如下
登录密钥从用户名更改为电子邮件。
[models.py]
class Account(AbstractBaseUser):
username = models.CharField(_('username'), max_length=30, unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
profile = models.CharField(_('profile'), max_length=255, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def user_has_perm(user, perm, obj):
return _user_has_perm(user, perm, obj)
def has_perm(self, perm, obj=None):
return _user_has_perm(self, perm, obj=obj)
def has_module_perms(self, app_label):
return self.is_admin
def get_short_name(self):
return self.first_name
@property
def is_superuser(self):
return self.is_admin
class Meta:
db_table = 'api_user'
swappable = 'AUTH_USER_MODEL'
Angular4更新用户信息的函数实现如下
使用函数 updateUserInfo 将新用户信息放入 Django REST Framework 中。
[component.ts]
updateUserInfo() {
this.authService.updateUserInfo({
email: this.editUserEmail,
username: this.editUserName,
profile: this.edtiUserProfile
})
.subscribe(
data => {
this.updateSuccessMessage = "success userinfo update";
this.updateErrorMessage = null;
this.authService.userInfo;
},
error => {
this.updateErrorMessage = "failed userinfo update";
this.updateSuccessMessage = null;
}
);
}
[service.ts]
updateUserInfo(userUpdateInfo) {
return this.http
.put(this.UpdateUserUrl,
userUpdateInfo,
this.jwt()
);
}
jwt() {
if (this.LoginToken) {
let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'JWT ' + this.LoginToken.token });
return new RequestOptions({ headers: headers });
}
}
Django中更新用户信息的视图和序列化器如下
[views.py]
class AuthInfoUpdateView(generics.UpdateAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = AccountSerializer
lookup_field = 'email'
queryset = Account.objects.all()
def get_object(self):
try:
instance = self.queryset.get(email=self.request.user)
return instance
except Account.DoesNotExist:
raise Http404
[serializers.py]
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'username', 'email', 'profile', 'password')
def create(self, validated_data):
return Account.objects.create_user(request_data=validated_data)
def update(self, instance, validated_data):
if 'password' in validated_data:
instance.set_password(validated_data['password'])
else:
instance = super().update(instance, validated_data)
instance.save()
return instance
现在发生的问题是更新电子邮件时的行为。
因为USERNAME_FIELD是邮件,更新邮件就得更新前端持有的token。
但是我不知道如何用新邮件获取token。
我认为保持用户身份验证的唯一方法是生成一个新令牌并将其发回,我不知道使用 django-rest-framework-jwt 执行此操作的另一种方法。
为此,您需要自定义 AuthInfoUpdateView
的 put
方法:
def put(self, request, *args, **kwargs):
serializer = self.serializer_class(self.get_object(), data=request.data, partial=True)
if serializer.is_valid():
instance = serializer.save()
# Generate a new token
payload = jwt_payload_handler(instance)
token = jwt.encode(payload, settings.SECRET_KEY)
response = JsonResponse({'token': token.decode('unicode_escape')})
response.status = 200
return response
else:
response = JsonResponse({'errors': serializer.errors})
response.status = 500
return response
就这么简单,您只需在前端更新令牌,而无需提示用户再次登录。
希望对您有所帮助!