JAVA网络爬虫
HttpClient

导航

 

认证组件

  1. 认证组件

    1. 使用方式介绍

      • 定义一个认证类

        class UserAuth():
          	def authenticate_header(self, request):
              	pass
            # 所有的逻辑都在authenticate上写
            def authenticate(self, request):
              	pass
        
      • 只需要认证的接口里面指定认证类

        class BookView(ModelViewSet):
          	# 指定认证类 UserAuth
          	authenticate_class = [UserAuth]
            # 获取queryset对象
          	queryset = BookInfo.objects.all()
            # 指定序列化类
            serializer_class = BookSerializer
          	
        

案列

  • 导入模块

     from django.http import JsonResponse
     
     from rest_framework.views import APIView
     from rest_framework.viewsets import ModelViewSet
     from rest_framework.exceptions import APIException
    
  • url.py

    from django.urls import re_path
    from .views import UserView, BookView
    
    urlpatterns = [
        re_path(r"^books/$", BookView.as_view({
            "get": "list",
            "post": "create"
        })),
    
        re_path(r"^books/(?P<pk>\d+)/$", BookView.as_view({
            "get": "retrieve",
            "put": "update",
            "delete": "destroy"
        })),
    
        re_path(r"^user/$", UserView.as_view())
    ]
    
    
  • model.py

    from django.db import models
    
    from datetime import datetime
    # from django.contrib.auth.models import AbstractUser
    
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name="用户名")
        password = models.CharField(max_length=40, verbose_name="用户密码")
        user_type_entry = (
            (1, "Delux"),
            (2, "SVIP"),
            (3, "VVIP")
        )
        user_type = models.IntegerField(choices=user_type_entry)
    
        class Meta:
            db_table = "db_user_info"
            verbose_name = "用户信息"
            verbose_name_plural = verbose_name
    
        def get_user_type_display(self):
            return self.user_type_entry[self.user_type]
    
    
    class UserToken(models.Model):
        # OneToOneField一对一关系
        # on_delete=models.CASCADE 当UserInfo数据表里面的数据被删除后UserToken里面的数据也随着被删除
        user = models.OneToOneField("UserInfo", on_delete=models.CASCADE, verbose_name="一对一关系")
        token = models.CharField(max_length=128, verbose_name="token")
    
        class Meta:
            db_table = "db_user_token"
            verbose_name = "用户token"
            verbose_name_plural = verbose_name
    
    
    class AuthorInfo(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者名称")
        age = models.IntegerField(verbose_name="作者年龄")
    
        class Meta:
            db_table = "db_author_info"
            verbose_name = "作者信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class PublishInfo(models.Model):
        name = models.CharField(max_length=32, verbose_name="出版社名称")
        city = models.CharField(max_length=32, verbose_name="出版社所在城市")
        email = models.EmailField(verbose_name="出版社邮箱")
    
        class Meta:
            db_table = "db_publish_info"
            verbose_name = "出版社信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class BookInfo(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")
        publishDate = models.DateField(default=datetime.now, verbose_name="出版日期")
    
        # max_digits小数位加整数位多少长度 decimal_places小数位长度为2
        price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="图书价格")
        publish = models.ForeignKey(PublishInfo, related_name="book", related_query_name="book_query", on_delete=models.CASCADE, verbose_name="出版社")
        # ManyToManyField多对多
        authors = models.ManyToManyField(AuthorInfo, verbose_name="图书作者")
    
        class Meta:
            db_table = "db_book_info"
            verbose_name = "图书信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.title
    
    
  • 序列化类

    from.models import BookInfo
    
    # 第一步: 导入模块
    from rest_framework import serializers
    
    from datetime import datetime
    
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            # 指定    要操作的模型类
            model = BookInfo
    
            # 指定序列化的字段
            fields = (
                "title",
                "price",
                "publishDate",
                "publish",
                "authors",
                "author_list",
                "publish_name",
                "publish_city"
            )
    
            # 指定那些字段是只写的
            # write_only只写的 (只写的 前端发送数据时要写它, 后端返回数据时没有它)
            extra_kwargs = {
                "publish": {"write_only": True},
                "authors": {"write_only": True}
            }
    
        # 自定义的字段
        # read_only只读的 (只读的 前端发送数据时不用写它, 后端返回数据时有它)
        publish_name = serializers.CharField(max_length=32, read_only=True, source="publish.name")
        publish_city = serializers.CharField(max_length=32, read_only=True, source="publish.city")
    
        author_list = serializers.SerializerMethodField()
    
        def get_author_list(self, book_obj):
            # 拿到queryset开始循环 [ {}, {}, {}]
            authors = []
    
            for author in book_obj.authors.all():
                authors.append(author.name)
            return authors
    
  • token值

    import uuid
    
    def generate_token():
      	# 把uuid残生出来的值转换成字符串, 然后以-切割在以空链接
        random_str = str(uuid.uuid4()).replace("-", "")
        return random_str
    
  • views.py

    from django.http import JsonResponse
    
    from rest_framework.views import APIView
    from rest_framework.viewsets import ModelViewSet
    from rest_framework.exceptions import APIException
    
    from .models import BookInfo, PublishInfo, AuthorInfo, UserInfo, UserToken
    from .app_serializers import BookSerializer
    from .utils import get_token
    
    # 第一步: 定义认证类
    class UserAuth(object):
        def authenticate_header(self, request):
            pass
    
        # 所有的逻辑都在authenticate上写
        def authenticate(self, request):
            # 获取token值
            user_token = request.GET.get("token", "")
            if user_token:
                try:
                    # 查询token值看有没有认证过的token
                    token = UserToken.objects.get(token=user_token)
                    # 后面权限会用到
                    return token.user.username, token.token
                except UserToken.DoesNotExist:
                    raise APIException("没有认证")
            else:
                raise APIException("没有认证")
    
    
    class BookView(ModelViewSet):
        # 第二步: 指定认证类 UserAuth
        authentication_classes = [UserAuth]
        queryset = BookInfo.objects.all()
        serializer_class = BookSerializer
    
    
    class UserView(APIView):
    
        def post(self, request):
    
            response = dict()
    
            # 定义需要的用户信息
            fields = {"username", "password"}
            # 定义一个用户信息字典
            user_info = dict()
    
            # request.data是前端发送过来的json数据
            # fields.issubset表示 fields是request.data.keys()的子集就显示True, 相反False
            if fields.issubset(set(request.data.keys())):
                # username = request.data.get("username", "")
                # password = request.data.get("password", "")
                for key in fields:
                  	# user_info添加个key的键值, request.data把key键的值赋值过去
                    user_info[key] = request.data[key]
    
            if user_info:
                # **user_info字典拆包 拆包成键值对, 而不是整个字典了 列 {"a":"bb"} 拆包成 a="bb"
                user_instance = UserInfo.objects.filter(**user_info).first()
    
                if user_instance is not None:
                    access_token = get_token.generate_token()
    
                    # 根据user=user_instance找到了直接更新, 把default的值复制给它
                    # 没有找到直接创建
                    # 意思就是有这个token更新token, 没有这个token创建一个token
                    UserToken.objects.update_or_create(user=user_instance, defaults={
                        "token": access_token
                    })
    
                    response["status_code"] = 200
                    response["status_message"] = "登入成功"
                    response["access_token"] = access_token
                    response["user_role"] = user_instance.get_user_type_display()
                else:
                    response["status_code"] = 201
                    response["status_message"] = "登入失败, 用户名或密码错误"
    
                return JsonResponse(response)
            else:
                return JsonResponse({"error": "参数不完整"})
    
  1. postman没有传递token值

    在这里插入图片描述

  2. postman传递token值
    在这里插入图片描述

多个认证类

  1. 多个认证类其他同上, 就视图改变了

      # 注意: 如果需要返回什么数据, 请在最后一个认证类中返回, 因为如果在前面返回, 在self._authentication()方法中会对返回值进行判断, 如果不为空, 认证的过程会终止.
      class UserAuth2(object):
        	def authenticate(self ,request):
            	raise APIException("认证失败")
              
      class UserAuth(object):
        	def authenticate_header(self, request):
            	pass
            
          def authenticate(self, request):
            	# 获取token值
              user_token = request.GET.get("token", "")
              if user_token:
                  try:
                      # 查询token值看有没有认证过的token
                      token = UserToken.objects.get(token=user_token)
                      # 后面权限会用到
                      return token.user.username, token.token
                  except UserToken.DoesNotExist:
                      raise APIException("没有认证")
              else:
                  raise APIException("没有认证")
                  
       class BookView(ModelViewSet):
           # 第二步: 指定认证类 UserAuth
            authentication_classes = [UserAuth, UserAuth2]
            queryset = BookInfo.objects.all()
            serializer_class = BookSerializer
    

认证类不写无用的authenticate_header方法

  1. 如果不希望每次都写无用的authenticate_header方法, 其他步足同上, 就认证类要继承BaseAuthentication

     from rest_framework.authentication import BaseAuthentication
      
      class UserAuth(BaseAuthentication):
          def authenticate(self, request):
            	# 获取token值
              user_token = request.GET.get("token", "")
              if user_token:
                  try:
                      # 查询token值看有没有认证过的token
                      token = UserToken.objects.get(token=user_token)
                      # 后面权限会用到
                      return token.user.username, token.token
                  except UserToken.DoesNotExist:
                      raise APIException("没有认证")
              else:
         				raise APIException("没有认证")
    

全局认证类

  1. 视图里不用指定认证类了, 就加了2步, 其他都不变
    1. 本项目settings.py
      REST_FRAMEWORK = {
        	# 这里可以用列表, 也可以用元祖
          'DEFAULT_AUTHENTICATION_CLASSES': [
            	# 这是路径 本项目的serializer下的authentication_classes下的UserAuth这个认证类
            	# 这个认证类还是痛上的那个认证类, 没改变
              'serializer.authentication_classes.UserAuth',
          ],
      }
      
    2. 把认证类放到这个路径下就好了, 千万记住, 视图上面就不需要添加认证了, 把视图上的
      authentication_classes = [UserAuth] 注释掉

认证组件源码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

posted on 2019-07-27 11:50  gmlgxx  阅读(40)  评论(0)    收藏  举报