Skip to main content
 首页 » 编程设计

python之使用 Django REST Framework 更新 USERNAME_FIELD 时如何处理 token

2024年08月20日30kenshinobiy

我正在使用 Django REST Framework 和 Angular 4 开发应用程序。
我不知道更新登录用户信息时 token 的处理。

Django的用户模型定制如下。
登录 key 从用户名更改为电子邮件。

[模型.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' 

Angular 4 UPDATE用户信息函数实现如下。
使用 updateUserInfo 函数将新用户信息放入 Django REST Framework。

[组件.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; 
    } 
  ); 
} 

[服务.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中更新用户信息的 View 和序列化器如下。

[ View .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 

[序列化程序.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 。

请您参考如下方法:

我认为保持用户身份验证的唯一方法是生成一个新 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 

就这么简单,您只需更新前端的 token ,而无需提示用户再次登录。

希望这对您有所帮助!