Django REST framework使用JWT的用户认证模式

权限认证

比如有一些API功能,是需要用户登录才能使用可以的
或者比如我要删除我这篇博客,也要验证我是作者才能删除

验证用户是否登录

from rest_framework.permissions import IsAuthenticated

class XXXViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin):
    
    permission_classes = (IsAuthenticated,)

验证操作是本人,需要自定义persssion

permissions.py

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, object):
        if request.method in permissions.SAFE_METHODS:
            return True

        return object.user == request.user

permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)

Django REST framework使用JWT的用户认证模式

  • 第一步: pip install djangorestframework-jwt

  • 第二步: 在url.py中配置

    from rest_framework_jwt.views import obtain_jwt_token
    urlpatterns = [
      ...
      url(r'^api-token-auth/', obtain_jwt_token),
      ...
    ]
  • 第三步: 在需要jwt认证的ViewSet的类里面设置

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication

class XXXViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
  authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

加上SessionAuthentication是为了在网站上调试方便
现在注册登录有两种方式:

  • 用户注册之后跳转到登录页面让其登录
  • 用户注册之后自动帮他登录了

第一种情况的话我们无需再做其他操作,第二种情况我们应该在用户注册之后返回jwt token的字段给前台,所以要做两步:

  • 因为返回字段是mixins帮我们做好了,所以我们要重写对应的方法来修改返回字段
  • 需要查看djangorestframework-jwt的源码找到生成jwt token的方法
from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler

class UserViewSet(CreateModelMixin, RetrieveModelMixin,UpdateModelMixin,viewsets.GenericViewSet):
   # 重写create方法
   def create(self, request, *args, **kwargs):
       serializer = self.get_serializer(data=request.data)
       serializer.is_valid(raise_exception=True)
       user = self.perform_create(serializer)
       
       # 在新建用户保存到数据库之后
       tmp_dict = serializer.data
       # 生成JWT Token
       payload = jwt_payload_handler(user)
       tmp_dict['token'] = jwt_encode_handler(payload)

       headers = self.get_success_headers(serializer.data)
       return Response(tmp_dict, status=status.HTTP_201_CREATED, headers=headers)

更多jwt的相关操作可以查看文档

动态serializers

这个使用之前说过的action属性就可以很方便的实现

class UserViewSet(CreateModelMixin, RetrieveModelMixin,UpdateModelMixin,viewsets.GenericViewSet):
    
    # 这个就不需要了
    #serializer_class = XXXSerializer

    def get_serializer_class(self):
        if self.action == 'create':
            return XXXSerializer
        elif self.action == 'list':
            return XXXSerializer
        return XXXSerializer

一些实用的Serializer fields

比如说我要发布这篇文章,需要上传我(用户)的id才能和这篇文章建立关联,但我们这个可以不用前台来上传

serializer.py

class XXXSerializer(serializers.ModelSerializer):
    # user默认是当前登录的user
    user = serializers.HiddenField(
        default = serializers.CurrentUserDefault()
    )

还有如果返回的字段逻辑比较复杂,可以用serializer.SerializerMethodField()来完成,例如:

class XXXSerializer(serializers.ModelSerializer):
    xxx = serializer.SerializerMethodField()
    
    # 把逻辑写在get_的前缀加xxx(字段名),然后返回
    def get_xxx(self, obj):
        # 完成你的业务逻辑
        return 

自定义用户认证

Django自带的登录是通过username和password来做登录的,但是现在很多网站或者app用手机号来来当做账号,这个时候就需要自定义用户认证:

from django.contrib.auth.backends import ModelBackend

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username=username)|Q(mobile=username))
            # 验证密码是否正确
            if user.check_password():
                return user
        except Exception as e:
            return None

用户注册的时候,如果你在后台查看的是明文,这是因为ModelSerializer在保存的时候直接明文保存了, 解决问题:

serializer.py

class UserRegSerializer(serializers.ModelSerializer):
    
    #重写create方法
    def create():
        user = super(UserRegSerializer,self).create(validated_data=validated_data)
        user.set_password(validated_data["password"])
        user.save()
        return user

或者也可以用django的信号量也可以解决

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
User = get_user_model()

@receiver(post_save, sender=User)
def create_user(sender, instance=None, created=False, **kwargs):
    if created:
        password = instance.password
        instance.set_password(password)
        instance.save()

然后还要app.py里面配置

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'
    
    def ready(self):
        import users.signals

你可能感兴趣的:(drf)