• 自定义频率、自动生成文档、JWT


    自定义频率、自动生成文档、JWT

    自定义频率

    #自定义频率需要写两个方法
    	#判断是否限次,没有限次True,否则False
    	def allow_request(self,request,view):
    	#限次后,返回等待的时间
    	def wait(self):
    #my_ipthrottle.py		
    	import time
        class IPThrottle():
            VISIT_DIC = {}
            def __init__(self):
                self.history_list = []
            def allow_request(self,request,view):
                ip = request.META.get('REMOTE_ADDR')
                ctime = time.time()
                if ip not in self.VISIT_DIC:
                    self.VISIT_DIC[ip] = [ctime,]
                    return True
                self.history_list=self.VISIT_DIC[ip] #当前访问者时间列表拿出来
                while True:
                    if ctime-self.history_list[-1] > 60:
                        self.history_list.pop()# 把最后一个移除
                    else:
                        break
                if len(self.history_list) < 3:
                    self.history_list.insert(0,ctime)
                    return True
                else:
                    return False
    
            def wait(self):
                ctime = time.time()
                return 60-(ctime-self.history_list[-1])	
    #views.py
        from rest_framework.views import APIView
        from rest_framework.response import Response
        class TestAPIView(APIView):
            def get(self,request,*args,**kwargs):
                return Response({'status':100,'msg':'请求成功'})
    #全局配置
        REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_CLASSES': (
                'app01.utils.my_ipthrottle.IPThrottle',
            ),
            'DEFAULT_THROTTLE_RATES': {
                'luffy': '3/m'  # key要跟类中的scop对应
            },
        }
    #局部配置
    	#views.py
        	from rest_framework.views import APIView
            from rest_framework.response import Response
            from app01.utils.my_ipthrottle import IPThrottle
            class TestAPIView(APIView):
                throttle_classes = [IPThrottle,]
                def get(self,request,*args,**kwargs):
                    return Response({'status':100,'msg':'请求成功'})
    	#settings.py
            REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_RATES': {
                'luffy': '3/m'  # key要跟类中的scop对应
            },
        }
    

    自动生成接口文档

    1 安装 pip3 install coreapi
    2 路由中配置,根据已有的路由生成接口文档
    	from rest_framework.documentation import include_docs_urls
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('test2/',views.Test2APIView.as_view()),
            #自动生成文档路由
            path('docs/',include_docs_urls(title='luffy'))#title自定义的站点标题
        ]
    3 继承自APIView及其子类可以自动生成文档,效果图看图1
        from rest_framework.views import APIView
        from rest_framework.response import Response
        class Test2APIView(APIView):
            """
            get:
            获取图书信息.
            post:
            增加图书
            put:
            修改图书信息
            delete:
            删除图书信息
            """
            def get(self,request,*args,**kwargs):
                return Response({'status':100,'msg':'请求成功'})
            def post(self,request,*args,**kwargs):
                ...
            def put(self,request,*args,**kwargs):
                ...
            def delete(self,request,*args,**kwargs):
                ...
    #继承视图集的,效果图看图2
    	from rest_framework.viewsets import GenericViewSet
        from rest_framework import mixins
    
        from app01.models import Book
        from app01.ser import BookModelSerializer
        class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet,mixins.DestroyModelMixin):
            """
            list:
            返回图书列表数据
            retrieve:
            返回图书详情数据
            latest:
            返回最新的图书数据
            read:
            修改图书的阅读量
            """
            queryset = Book
            serializer_class = BookModelSerializer
    #如果遇到报错,AttributeError: 'AutoSchema' object has no attribute 'get_link',配置下面这句加入即可
        REST_FRAMEWORK = {
         'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
            # 新版drf schema_class默认用的是rest_framework.schemas.openapi.AutoSchema}
    

    图1

    图2

    Json Web Token(jwt)简单使用

    #原理
    	1 jwt分三段式:头(head)、体(payload)、签名(sgin)
    	2 头和体是可逆加密,让服务器可以反解除user对象,签名不可逆加密,保证整个token的安全性
    	3 这3部分都是采用json格式的字符串,进行加密,可逆加密采用base64,不可逆采用hash(md5)
    	4 头包含的是基本信息:如公司信息,项目组信息
    	5 体包含的是关键信息:用户主键,用户名,签发时客户端信息(设备号、地址),过期时间
    	6 签名包含的是安全信息:加密过的头和加密过的体加服务器不对外公开的安全码,之后经过hash(md5)加密
    #效验
    	1 将token按.拆分为三段字符串,第一段是头加密结果,不用做人去处理
        2 第二段是体加密结果,反解出用户主键,通过主键从user表获得当前登录用户,过期时间和设备信息都是安全信息,确保token没过期,切是同一设备
        3 再用 第一段和第二段加服务器安全码 不可逆hash(md5)加密,与第三段签名,进行碰撞效验,通过后才能代表第二段效验得到的user对象就是合法的登录用户
    #drf项目的jwt认证完整使用(重点)
    	1 用账号密码访问登录接口,登录接口逻辑中调用token算法,得到token,返回给客户端,客户端自动存到cookies
    	2 效验token的算法应该写认证类中(在认证类中调用),全局配置认证组件,所有视图都会经过认证类,请求带了token就可以反解出user对象,在视图中就能request.user获取到登录用户
    	#登录接口需要认证类和权限类禁用
    #简单实用
    	1 安装 pip3 install django-rest-framework-jwt
    	2 新建一个User表,继承AbstractUser
    		#models.py
    		from django.contrib.auth.models import AbstractUser
            class UserInfo(AbstractUser):
                mobilephone = models.CharField(max_length=11)
    	3 创建超级用户
    		PyCharm终端python3 manage.py createsuperuser
    	4 urls.py中加入路由
    	    from rest_framework_jwt.views import obtain_jwt_token
        path('login/', obtain_jwt_token),
       	#全局配置
       		REST_FRAMEWORK = {
                # 认证模块
                'DEFAULT_AUTHENTICATION_CLASSES': (
                    'rest_framework_jwt.authentication.JSONWebTokenAuthentication',),}
    	#局部配置,视图类里加上authentication_classes
    		from rest_framework.views import APIView
            from rest_framework.response import Response
            from rest_framework_jwt.authentication import JSONWebTokenAuthentication
            class TestAPIView(APIView):
                # authentication_classes = [JSONWebTokenAuthentication,]
                def get(self,request,*args,**kwargs):
                    return Response('ok')
    	#app中一定要注册
    		INSTALLED_APPS = [
                'rest_framework_jwt',
                'rest_framework',]
    	#携带token注意事项,JWT空格再加token看图1  ,
    	#简单使用jwt是内置的不带Authorization也可以通过,之后需要自定义JWT认证         
    

    图1

    自定义JWT认证

    from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
    from rest_framework_jwt.authentication import jwt_decode_handler
    from rest_framework import exceptions
    class MyAuthentication(BaseJSONWebTokenAuthentication):
        def authenticate(self, request):
            jwt_value = str(request.META.get('HTTP_AUTHORIZATION'))
            #认证
            try:
                payload = jwt_decode_handler(jwt_value)
            except Exception:
                raise exceptions.AuthenticationFailed("认证失败")
            user = self.authenticate_credentials(payload)
            return user,None
    #全局配置
        REST_FRAMEWORK = {
                'DEFAULT_AUTHENTICATION_CLASSES':			    				('app01.utils.authenticate.MyAuthentication',),}
    #局部配置
        from rest_framework.views import APIView
        from rest_framework.response import Response
        #自定义jwt认证
        from app01.utils.authenticate import MyAuthentication
        class TestAPIView(APIView):
            authentication_classes = [MyAuthentication,]
            def get(self,request,*args,**kwargs):
                return Response('ok')	
    #使用方式不需要JWT加空格了看下图,其他配置跟上面简单使用一致            
    

    控制用户登录才能访问

    #用户通过内置的jwt认证获得token,permission_classes就能获取到登录用户,否则不登录就无法访问
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
        from rest_framework.permissions import IsAuthenticated
        from rest_framework.views import APIView
        from rest_framework.response import Response
        class TestAPIView(APIView):
            authentication_classes = [JSONWebTokenAuthentication,]
            permission_classes = [IsAuthenticated, ]
            def get(self,request,*args,**kwargs):
                return Response('ok')  
    

    控制登录接口返回的数据格式

    #第一种方案
    	自己写登录接口
    #第二种方案,控制内置的登录接口返回的数据格式
    	#还是采用内置的jwt认证,所以携带token还是得JWT空格token的方式,不然不会给你认证
    	#app01utilsjwt_response.py
            def jwt_response_payload_handler(token, user=None, request=None):
                return {
                    'status':100,
                    'msg':'登录成功',
                    'username':user.username,
                    'token': token,
                }
        #settins.py
            JWT_AUTH = {
            'JWT_RESPONSE_PAYLOAD_HANDLER':'app01.utils.jwt_response.jwt_response_payload_handler',
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # token过期时间,手动配置 
        }
    

    自定义基于JWT权限类

    #app01utilsmyjwt.py
        import jwt
        from rest_framework.authentication import BaseAuthentication
        from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
        from rest_framework.exceptions import AuthenticationFailed
        from rest_framework_jwt.utils import jwt_decode_handler
        from app01 import models
        
        #第一种
        class MyJwtAuthentication(BaseAuthentication):
            def authenticate(self, request):
                jwt_value=request.META.get('HTTP_AUTHORIZATION')
                if jwt_value:
                    try:
                        payload = jwt_decode_handler(jwt_value)
                    except jwt.ExpiredSignature:
                        raise AuthenticationFailed('签名过期')
                    except jwt.InvalidTokenError:
                        raise AuthenticationFailed('用户非法')
                    except Exception as e:
                        raise AuthenticationFailed(str(e))
                    #第一张获取用户名方式,数据库查
                    # user = models.User.objects.get(pk=payload.get('user_id'))
                    #第二种,不查库
                    user = models.User(id=payload.get('user_id'),username=payload.get('username'))
                    return user,jwt_value
                raise AuthenticationFailed('你没有携带认证信息')
    
    
    
        #第二种
        class MyJwtAuthentication2(BaseJSONWebTokenAuthentication):
            def authenticate(self, request):
                jwt_value = request.META.get('HTTP_AUTHORIZATION')
                if jwt_value:
                    try:
                        payload = jwt_decode_handler(jwt_value)
                    except jwt.ExpiredSignature:
                        raise AuthenticationFailed('签名过期')
                    except jwt.InvalidTokenError:
                        raise AuthenticationFailed('用户非法')
                    except Exception as e:
                        raise AuthenticationFailed(str(e))
                    user = self.authenticate_credentials(payload)
                    return user, jwt_value
                raise AuthenticationFailed('你没携带认证信息')
    #全局配置
        REST_FRAMEWORK = {
            "DEFAULT_AUTHENTICATION_CLASSES": ['app01.utils.myjwt.MyJwtAuthentication2']
        }
    #局部配置
        from rest_framework.permissions import IsAuthenticated
        from rest_framework.views import APIView
        from rest_framework.response import Response
    
        from app01.utils.myjwt import MyJwtAuthentication
        class TestAPIView(APIView):
        	#局部认证
            authentication_classes = [MyJwtAuthentication,]
            permission_classes = [IsAuthenticated, ]
            def get(self,request,*args,**kwargs):
                return Response('ok')
    

    手动签发token(多方式登录)

    #使用用户名,手机号,邮箱都可以登录
    #前端需要传的格式
    	{
    	"username":"用户名或手机号或邮箱",
    	"password":"密码"
    	}
    #views.py
        from rest_framework.viewsets import ViewSet
    
        from app01.utils.ser import LoginModelSerializer
        class Login2View(ViewSet):  # 跟上面完全一样
            authentication_classes = []
            def login(self, request, *args, **kwargs):
                # 1 需要 有个序列化的类
                login_ser = LoginModelSerializer(data=request.data,context={'request':request})
                # 2 生成序列化类对象
                # 3 调用序列号对象的is_validad
                login_ser.is_valid(raise_exception=True)
                token=login_ser.context.get('token')
                # 4 return
                return Response({'status':100,'msg':'登录成功','token':token,'username':login_ser.context.get('username')})
    #app01utilsser.py
        from rest_framework import serializers
        from app01 import models
        import re
        from rest_framework.exceptions import ValidationError
    
        from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
        class LoginModelSerializer(serializers.ModelSerializer):
            username=serializers.CharField()  # 重新覆盖username字段,数据中它是unique,post,认为你保存数据,自己有校验没过
            class Meta:
                model=models.User
                fields=['username','password']
    
            def validate(self, attrs):
    
                print(self.context)
    
                # 在这写逻辑
                username=attrs.get('username') # 用户名有三种方式
                password=attrs.get('password')
                # 通过判断,username数据不同,查询字段不一样
                # 正则匹配,如果是手机号
                if re.match('^1[3-9][0-9]{9}$',username):
                    user=models.User.objects.filter(mobile=username).first()
                elif re.match('^.+@.+$',username):# 邮箱
                    user=models.User.objects.filter(email=username).first()
                else:
                    user=models.User.objects.filter(username=username).first()
                if user: # 存在用户
                    # 校验密码,因为是密文,要用check_password
                    if user.check_password(password):
                        # 签发token
                        payload = jwt_payload_handler(user)  # 把user传入,得到payload
                        token = jwt_encode_handler(payload)  # 把payload传入,得到token
                        self.context['token']=token
                        self.context['username']=user.username
                        return attrs
                    else:
                        raise ValidationError('密码错误')
                else:
                    raise ValidationError('用户不存在')
                    
    

    JWT配置参数

    #settings.py
        import datetime
        JWT_AUTH = {
            'JWT_RESPONSE_PAYLOAD_HANDLER':'app01.utils.jwt_response.jwt_response_payload_handler',
            'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # 过期时间,手动配置
        }
    

    基于角色的权限控制(Django内置的的auth体系)

    #Role-Based Access Control(RBAC)是基于角色的访问控制,用于公司内部系统
    #Django的auth就是一套基于RBAC的权限系统
    #django中,
    	user表
    	permission表
    	group表
    	user_groups表是user和group的中间表
    	group_permissions表是group和permission中间表
    	user_permissions表是user和permission中间表
    	#后端,需要三大认证(认证,权限,频率)
    

    Django缓存

    # 前端混合开发缓存的使用
    	-缓存的位置,通过配置文件来操作(以文件为例)
        -缓存的粒度:
        	-全站缓存
            	中间件
                MIDDLEWARE = [
                    'django.middleware.cache.UpdateCacheMiddleware',
                    。。。。
                    'django.middleware.cache.FetchFromCacheMiddleware',
                ]
                CACHE_MIDDLEWARE_SECONDS=10  # 全站缓存时间
            -单页面缓存
            	在视图函数上加装饰器
                from django.views.decorators.cache import cache_page
                @cache_page(5)  # 缓存5s钟
                def test_cache(request):
                    import time
                    ctime=time.time()
                    return render(request,'index.html',context={'ctime':ctime})
            	
            -页面局部缓存
            	{% load cache %}
                {% cache 5 'name' %}  # 5表示5s钟,name是唯一key值
                 {{ ctime }}
                {% endcache %}
            	
        
    # 前后端分离缓存的使用
    	- 如何使用
            from django.core.cache import cache
            cache.set('key',value可以是任意数据类型)
            cache.get('key')
        -应用场景:
        	-第一次查询所有图书,你通过多表联查序列化之后的数据,直接缓存起来
            -后续,先去缓存查,如果有直接返回,没有,去连表查,返回之前再缓存
    

    base64使用

    #base64编码和解码,base63可变长,可反解,hash(md5)固定长度,不可逆加密
    #base64编码
    	import base64
    	import json
    	dic = {'name':'joab','age':18,'sex':'男'}
    	dic_str = json.dumps(dic)
    	
    	ret = base64.b64encode(dic_str.encode('utf-8'))
    #base64解码
    	ret2 = base64.b64decode(ret)
    
  • 相关阅读:
    zabbix监控
    ipv4固定ip地址
    CentOS7 内核优化 修改参数
    流媒体服务器 red5
    linux安装git
    zabbix-钉钉报警媒介
    Windows下利用IIS建立网站并实现局域网共享
    docker的简单操作和端口映射
    docker概述和安装及基本操作
    VMware Workstation创建Windows2012server虚拟机
  • 原文地址:https://www.cnblogs.com/linqiaobao/p/13355821.html
Copyright © 2020-2023  润新知