当前位置:   article > 正文

DRF~ day09 之全局异常、接口文档、jwt介绍和原理、base64编码和解码_jwt 文档

jwt 文档

DRF之之全局异常、接口文档、jwt介绍和原理、base64编码和解码



1、全局异常

1.1、全局异常源码介绍

1、只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler
查看源码:如下

模块: import rest_framework.settings
模块: from rest_framework.views import APIView

    import rest_framework.settings  # 从settings中找源码
    源码84行左右
    # Exception handling
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
    'NON_FIELD_ERRORS_KEY': 'non_field_errors',
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、drf只要出了异常,就会执行:‘EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’ 这个函数

执行这个’EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’
就会执行 rest_framework.views.exception_handler


'''
去继承的APIView中的dispatch方法中的       
        except Exception as exc:
            response = self.handle_exception(exc)
异常代码执行handle_exception方法


    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)
    
        # 走这一行执行self.handle_exception(exc)代码然后执行handle_exception方法
        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

'''
执行handle_exception 方法
时就会执行方法中exception_handler = self.get_exception_handler()  这一行代码
但是这一行代码就是  前面 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler’中的rest_framework.views.exception_handle函数


    def handle_exception(self, exc):
        """
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        """
        if isinstance(exc, (exceptions.NotAuthenticated,
                            exceptions.AuthenticationFailed)):
            # WWW-Authenticate header for 401 responses, else coerce to 403
            auth_header = self.get_authenticate_header(self.request)

            if auth_header:
                exc.auth_header = auth_header
            else:
                exc.status_code = status.HTTP_403_FORBIDDEN
        
        # 最终执行这一行代码
        exception_handler = self.get_exception_handler()

        context = self.get_exception_handler_context()
        response = exception_handler(exc, context)

        if response is None:
            self.raise_uncaught_exception(exc)

        response.exception = True
        return response
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

3、drf只要出了异常,就会执行:‘EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’ 这个函数
看这个函数 rest_framework.views.exception_handler

4、导入这个执行异常函数的模块
from rest_framework.views import exception_handler
点进去里面就是def exception_handler(exc, context):函数

下面是源代码

'''
def exception_handler(exc, context):
    """
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    """
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()

    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    return None
'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

1.2、验证drf出现异常就会执行上面exception_handler函数

场景:只要drf出现异常就会执行上面exception_handler函数
设置drf的异常查看是否执行exception_handler函数

  • 设置源代码(验证完成要改回来)
    在这里插入图片描述

  • 要执行的drf代码

# 场景只要drf出现异常就会执行上面exception_handler函数
# 设置drf的异常查看是否执行exception_handler函数
from rest_framework.exceptions import APIException
from app01 import models


class BookView(APIView):
    def get(self, request):
        # 1、接受前端的信息
        name = request.query_params.get('name')
        pwe = request.query_params.get('pwd')

        # 在这里设置异常验证是否drf报错是否执行了源代码中的exception_handler函数
        # 这里了源代码中的exception_handler函数 设置了输出函数,
        # 只要执行exception_handler函数,打印输出‘我不信’
        raise APIException('我出错误了')

        # 2、查询数据库信息
        book_obj = models.Book.objects.all()  # 查询所有数据

        if name:
            book_obj = book_obj.order_by(name)
        else:
            book_obj = book_obj.filter(name__contains=name)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 验证结果展示

用postman模拟前端发送数据
在这里插入图片描述

后端执行代码结果:
在这里插入图片描述

到这里就验证了上面的问题
drf出现异常就会执行exception_handler函数

1.3、自定义全局异常处理

到这里就有一个问题,把源码改了之后自己的drf代码可以执行,但是把drf代码给别人就实现不了功能,所以我们可以自定义一个函数,配置一下,以后出了异常,执行我们自己的函数,我们称这个函数为:自定义异常

1、创建一个文件(exceptions.py)用来写自定义异常的函数


# 设置
'''
def exception_handler(exc, context):

    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()

    # 这里就是判断exc是不是APIException的对象,如果是就返回下面return Response(data, status=exc.status_code, headers=headers)
    # 如果不是就返回 return None
    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        # 这里是处理异常详细数据有多种形式
        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    return None
'''





# 如果异常对象是drf的APIException对象,就会返回Response
# exception_handler只处理了drf的异常,其它的异常需要我们自己处理
# 如果异常对象不是drf的APIException对象,就会返回None

# isinstance()   判断一个对象是不是某个类的对象,返回bool值  isinstance(对象,类)
# issubclass()   判断一个类,是不是另一个类的子类,返回bool值

from rest_framework.response import Response
from rest_framework.views import exception_handler


def common_exception_handler(exc, context):
    # 只要走到这里,一定出异常了,我们正常的项目要记录日志(后面讲)

    # 这里调用exception_handler函数方法
    # 这个方法有两种可能:一个是Response对象,一个是None
    res = exception_handler(exc, context)
    # 这里的if res 表示:如果有值,代表的是drf的APIException对象的错误
    # if判断下面处理APIException对象的错误信息
    # 如果没有值,代表的是,其他异常
    # 这里统一返回错误信息格式 return Response({'code': 505, 'msg': '有问题了', 'data': 'jdksajdk'})
    if res:
        # 只要代码执行到这里,就说明是drf异常,它APIException处理了
        # 获取错误的信息
        if isinstance(res.data, dict):
            detail = res.data.get('detail')
        else:
            detail = res.data
        # 这里返回的信息是定制给前端的错误信息
        return Response({'code': 505, 'msg': detail})
    else:
        # 说明是其它异常,它是APIException没有处理的异常

        # 这里返回的信息是定制给前端的错误信息
        # return Response({'code': 4556, 'msg': "系统异常,请联系系统管理员"})
        return Response({'code': 4556, 'msg': str(exc)})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

2、写视图类代码

from app01 import models
from rest_framework.views import APIView

class BookView(APIView):
    def get(self, request):
        # 1、接受前端的信息
        name = request.query_params.get('name')
        pwe = request.query_params.get('pwd')

        # 在这里设置异常验证是否drf报错是否执行了源代码中的exception_handler函数
        # 这里源代码中的exception_handler函数 设置了输出函数,
        # 只要执行exception_handler函数,打印输出‘我不信’

        # raise APIException('我出错误了')  # 设置drf异常,前端能看到这个中文
        raise Exception('django中的异常数据')  # 设置django异常
        # # 其他错误
        # l = [1, 2, 3]
        # print(l[9])

        # 2、查询数据库信息
        book_obj = models.Book.objects.all()  # 查询所有数据

        if name:
            book_obj = book_obj.order_by(name)
        else:
            book_obj = book_obj.filter(name__contains=name)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

3、路由

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),

    # 开始设置异常的路由
    path('books/', views.BookView.as_view()),

]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4、配置文件配置

# 自定义异常配置文件中要加入
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
}
  • 1
  • 2
  • 3
  • 4

5、展示

drf异常数据返回
在这里插入图片描述
django异常错误
在这里插入图片描述
其他异常错误
在这里插入图片描述

1.4、总结

# 对于前端来讲,后端即便报错,也要返回统一的格式,前端便于处理
{code:999,msg:'系统异常,请联系系统管理员'}


# 只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler

### 注意:exception_handler
    # 如果异常对象是drf的APIException对象,就会返回Response
    # exception_handler只处理了drf的异常,其它的异常需要我们自己处理
    # 如果异常对象不是drf的APIException对象,就会返回None
    
# 补充:
    # isinstance()   判断一个对象是不是某个类的对象  isinstance(对象,类)
    # issubclass()   判断一个类,是不是另一个类的子类
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

二、接口文档

# 后端把接口写好后
	-登录接口
    -注册接口
    -查询所有图书带过滤接口
# 前端人员需要根据接口文档,进行前端开发

# 前后端需要做对接----》对接第一个东西就是这个接口文档---》前端照着接口文档开发

# 公司3个人,每个人开发了10个接口,3个人都要同时写接口文档

# 接口文档的编写形式
	-1 world,md,编写,大家都可以操作,写完放在git,公司的文档管理平台上
    -2 第三方的接口文档平台(收费)
    	https://www.showdoc.com.cn/
    -3 公司自己开发接口文档平台
    -4 公司使用开源的接口文档平台,搭建
    	-YAPI:百度开源的
        -https://zhuanlan.zhihu.com/p/366025001
        
    -5 项目自动生成接口文档
    	-coreapi
        -swagger
        
        
# 使用coreapi自动生成接口文档
	-使用步骤:
    	-1 安装:pip3 install coreapi
		-2 加一个路由
        	from rest_framework.documentation import include_docs_urls	
        	urlpatterns = [
            	path('docs/', include_docs_urls(title='站点页面标题'))
        	]
        -3 在视图类上加注释
        
        -4 配置文件中配置:
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
        -5 表模型或序列化类的字段上写 help_text--->会显示在接口文档的字段介绍上
        
        -6 访问地址:
        http://127.0.0.1:8000/docs/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

三、jwt介绍和原理

3.1、Cookie,Session,Token发展史

3.1.1、 Cookie

cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

3.1.2、 Session

服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

3.1.3、 cookie和session的区别

session是存储服务器端,cookie是存储在客户端,所以session的安全性比cookie高

获取session里的信息是通过存放在会话cookie里的session id获取的。而session是存放在服务器的内存中里,所以session里的数据不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里。

session的信息是通过sessionid获取的,而sessionid是存放在会话cookie中

当浏览器关闭的时候会话cookie消失,所以sessionid也就消失了,但是session的信息还存在服务器端,只是查不到所谓的session,但它并不是不存在

3.1.4、 Token

在Web领域基于Token的身份验证随处可见。在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式。

以下几点特性会让你在程序中使用基于Token的身份验证
无状态、可扩展
支持移动设备
跨程序调用
安全
那些使用基于Token的身份验证的大佬们:大部分你见到过的API和Web应用都使用tokens。例如Facebook, Twitter, Google+, GitHub等。

CORS (跨域资源共享)
当我们扩展应用程序,让数据能够从不同设备上访问时,跨域资源的共享会是一个让人头疼的问题。在使用 Ajax 抓取另一个域的资源时(移动端访问我们的 API 服务器),可能会出现禁止请求的情况。

CSRF (跨站请求伪造)
用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。
在这些问题中,可扩展性是最突出的。因此我们有必要去寻求一种更有行之有效的方法。

基于Token的验证原理
基于 Token 的身份验证是无状态的,我们不用将用户信息存在服务器或 Session 中。这种概念解决了在服务端存储信息时的许多问题。没有 session 信息意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录和已经登录到了哪里。

实现思路:
1.用户登录校验,校验成功后就返回Token给客户端。
2.客户端收到数据后保存在客户端
3.客户端每次访问API是携带Token到服务器端。
4.服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码
当我们在程序中认证了信息并取得 token 之后,我们便能通过这个 token 做许多的事情。我们甚至能基于创建一个基于权限的token传给第三方应用程序,这些第三方程序能够获取到我们的数据(当然只限于该 token 被允许访问的数据)

# 总结
	-会话管理
    -cookie:客户端浏览器的键值对
    -session:服务的的键值对(djangosession表,内存中,文件,缓存数据库)
    -token:服务的生成的加密字符串,如果存在客户端浏览器上,就叫cookie
    	-三部分:头,荷载,签名
        -签发:登录成功,签发
        -认证:认证类中认证
# jwt:Json web token (JWT),web方向的token认证
	-长得样子:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

四、base64编码和解码

# base64并不是一种加密反射,只是编码解码方式
#  字符串,可以转成base64编码格式:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 解码成base64

  • 1
  • 2
  • 3
  • 4
import json
import base64

# d = {'user_id': 1, 'username': "lqz"}
#
# d_str = json.dumps(d)
# print(d_str)
# # 对字符串进行bashe64 编码
# res=base64.b64encode(bytes(d_str,encoding='utf-8'))
# print(res)  # eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImxxeiJ9


# 解码
# res=base64.b64decode('TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=')
# print(res)


# 记住: base64 编码,长度一定是4的倍数。如果不够,用 = 补齐


# base64的用途
'''
1 互联网中,前后端数据交互,使用base64编码
2 jwt 字符串使用base64编码
3 互联网中一些图片,使用base64编码

'''

s = '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'
res = base64.b64decode(s)
with open('code.png', 'wb') as f:
    f.write(res)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

总结

以上就是今天要讲的内容,本文仅仅简单介绍了的使用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/608240
推荐阅读
相关标签
  

闽ICP备14008679号