kookie,session,token介绍与drf-jwt的使用

kookie,session,token介绍与drf-jwt的使用

1.无cookie时期
	很久以前web基本上就是文档浏览器而已,单方向输出的,供人浏览所以不需要记录是否在一段时间内浏览了哪些文档,每次见面都是第一次

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

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

2.cookie+session认证时期
	随着交互式互联网的兴起例如,像购物平台,需要登录的网站等的崛起,马上就面临一个问题,就是需要管理会话,不能每次都只如初见,必须需要保存状态,并且将每个人都区分开,但是由于Http请求是误装填的所以相处的办法就是给大家发一个会话表示session id来区分请求,这样就可以知道谁是谁了,你也就能证明你自己是你自己

session

1.session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

2.session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

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

4.虽然上方那样解决了登录状态的问题,那么又迎来了一个新的问题,用户的session只需要自己保存即可,但是服务器却是需要将所有的session进行保存,用户量打的话服务器就有点吃不消了,并且也是一笔巨大的开销,严重限制了服务器的扩展能力

token

1.token认证
	如何解决上方session的问题,只让用户去自己保存自己的session,客户端只进行验证就可以通过访问,也就是给它发一个令牌(token)用来验证,里面包含了用户的id,下一次在访问的时候直接带着token在响应头中即可,但是token容易被伪造,所以就需要,进行一个加密处理也就是签名内部有用户信息加盐然后再进行加密即可,这样服务端就不需要保存session。

2.token的组成
	第一段 头 公司信息,加密信息...{} Header
	第二段 荷载 真正的数据 {"name":"joseph","id":1} 
	第三段 签名 使用第一段和第二段信息,通过某种加密方式进行加密得到一串数字,大写字母,小写字母和等号的加密字符串

3.token的使用阶段
	登陆成功后的签发token阶段,会经过token生成的三段
	登陆成功后访问某个接口的验证阶段 验证token是否合法


jwt原理介绍

1.jwt的组成
	json web token(JWT),token应用于web方向被称为jwt

2.jwt构成和工作原理
	JWT就是一段字符串,由三段信息构成,江浙三段信息文本用.(句点符)的形式链接在一起JWT字符串,就像这样:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
3.第一段是公司信息,第二段是用户信息(荷载),第三段则是将头和荷载进行加密加盐处理后的签名

4.header 头
	声明类型(JWT)
	声明加密的算法,通常使用(HMAC,SHA256)进行加密
	公司信息:
    {
        'typ': 'JWT',
        'alg': 'SHA256'
    }
	变成了(base64的编码):eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    
5.payload: 荷载
    exp:jwt的过期时间,这个过期时间必须大于签发时间
    iat: jwt的签发时间
    用户信息:
    {
        "exp": "879456178946532",
        "name": "joseph",
        "userid": 1
    }
    变成了(base64的编码):eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

6.signature: 签名
	将头和荷载加密后得到的:
	变成了(base64的编码):TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

7.secret(秘密,加密)是保存在服务器端的(加密方式和加盐),jwt的签发生成也是	在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,他就是你服务端的私钥,在任何场景都不应该泄露出去,一旦客户端得知这个加密方式那么就意味着客户端可以自我签发jwt了

8.jwt使用流程
	签发:登录接口签发
	认证:认证类认证

base64编码和解码

1.base64 可以将字符串编码成base64的编码格式(大小写字母,数字和=(等号))TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

2.base64可以把base64编码的字符串,解码回原来的格式

3.应用场景:
	jwt中使用
	网络中传输的字符串可以使用base64编码
	网络中的传输图片也可以使用base64的编码

4.编码解码
    import json  # 导入json模块
    import base64  # 导入base64模块

    # 创建一个段数据
    dic = {'user_id':'1','name':'joseph','age':'21','hobby':'read'}
    # 使用json模块序列化该数据
    data = json.dumps(dic)
    # 使用base64进行加密处理
    res = base64.b64encode(data.encode('utf-8'))
    # 打印b'eyJ1c2VyX2lkIjogIjEiLCAibmFtZSI6ICJqb3NlcGgiLCAiYWdlIjogIjIxIiwgImhvYmJ5IjogInJlYWQifQ=='
    print(res)

    # 保存图片
    f = open('img/img.png','rb')  # 首先将一个图片转为二进制
    png = base64.b64encode(f.read())  # 使用base64进行加密处理
    print(png)  # 打印该二进制
    img = base64.b64decode(png)  # 使用base64进行解码
    print(img)  # 打印
    with open(r'png.png','wb')as f:  # 将该二进制存储到文件夹中
        f.write(img)  

drf-jwt快速使用

1.jwt 签发(登录接口) 认证 (认证类)
django中使用jwt
    可以自己写
    https://github.com/jpadilla/django-rest-framework-jwt  (比较老)
    https://github.com/jazzband/djangorestframework-simplejwt (比较新)
2.jwt使用
    1.安装drf-jwt模块
        pip3 install djangorestframework-jwt
    2.迁移表,因为他默认使用auth的user表签发token
    3.创建超级用户(auth的user表中要有记录)
    4.使用这个不需要写登录接口了,如果是使用auth的user表作为用户表他可以快速签发
    5.签发(就是在登录的时候给我们创建token):只需要在路由中配置即可(视图函数都不需要写,他已经帮我们写好了登录接口),我们直接访问改接口即可,就可以看到我们的token
        from rest_framework_jwt.views import obtain_jwt_token
        from app01 import views
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('login/', obtain_jwt_token),
            path('test/', views.TestView.as_view()),
        ]
	6.认证类编写
    from rest_framework.views import APIView
    # Create your views here.
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from rest_framework.permissions import IsAuthenticated
    from rest_framework.response import Response
    class TestView(APIView):
        authentication_classes = [JSONWebTokenAuthentication,]
        permission_classes = [IsAuthenticated,]
        def get(self,request):
            return Response('ok')
    7.前端在访问时,token需要放在请求头中
    	Authorization:jwt token串(空格不可以少)

drf-jwt修改返回格式

1.使用jwt的登录登录成功后,前端只能看到token,如果我们想要给它加上别的东西一起显示出来那么就需要给它重写方法
    {
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6Impvc2VwaCIsImV4cCI6MTY2NTU3MjY3NSwiZW1haWwiOiI1MjBAcXEuY29tIn0.GsrVn6ieySxSh_9SSxZhinOTy56gjRqDPCqTD2urGPw"
    }

2.写一个函数,函数返回什么那么前端就会看到什么,配置在配置文件中我们就可以看到格式
    2.1写一个函数:
        # from rest_framework_jwt.views import jwt_response_payload_handler

        def jwt_response_payload_handler(token,user=None,request=None):
            return {
                'code': 100,
                'msg': '登录成功',
                'username': user.username,
                'token':token
        }
    2.2配置文件:
        JWT_AUTH={
            'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.loger.jwt_response_payload_handler',
        }

自定义user表,签发token

1.我们自定义写user表,签发token
	1.1首先要创建一个userinfo表
        from django.db import models
        class UserInfo(models.Model):
            username = models.CharField(max_length=32,verbose_name='用户名')
            password = models.CharField(max_length=32, verbose_name='密码')
	2.登录接口
        urlpatterns = [
            path('user/login/',views.UserView.as_view())
        ]
	3.视图函数
        from rest_framework.exceptions import APIException
        from rest_framework_jwt.settings import api_settings
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        from .models import UserInfo
        class UserView(APIView):
            def post(self,request):
                try:
                    username = request.data.get('username')
                    password = request.data.get('password')
                    # 根据user,签发token,三个部分,使用使用djagnorestframework-jwt模块提供的其单反token的函数
                    user = UserInfo.objects.get(username=username, password=password)
                    # 通过user对象拿到用户信息
                    payload = jwt_payload_handler(user)
                    # 根据payload拿到token
                    token = jwt_encode_handler(payload)
                    print(payload)
                    print(token)
                    return Response({'code':100, 'msg':'登陆成功', 'token':token})
                except Exception:
                    raise APIException('用户名或密码错误')

X_FORWARDED_FOR

1.X_FORWARDED_FOR(XFF)是用来识别HTTP代理或负载均衡方式连接到web非要我也去的服务端的客户端最原始的IP地址的HTTP请求头字段。squid缓存代理服务器的开发人员最早引入了这一HTTP头字段,并由IETF在HTTP头字段标准化草案中正式提出。
2.当今多数的缓存服务器的用户为大型ISP,为了通过缓存的方式来降低他们的外部带宽,他们常常通过鼓励或强制用户使用dialing服务器来接入互联网。有些情况下,这些代理服务器是透明代理,用户喊谁呢知不知道自己在使用代理上网
3.如果没有XFF或者另外一种类似技术,所有通过地阿里服务器的链接只会显示代理服务器的IP地址,而非连接发起的原始IP地址,这样的代理服务器世界和是哪个充当了匿名服务提供者的角色,如果连接的原始IP不可得,恶意访问的检测与预防的难度将大大增加。XFF的有效依赖于地阿里服务器提供的连接原始IP的真实性,因此,XFF的有效使用应该保证服代理务器是可信的,比如可以通过创建可信服务器白名单

单机结构

大家最熟悉的应该就是单机结构,一个系统业务很小的时候所有的代码都放在一个项目中就好了,然后这个项目部署在一台服务器上就好了,整个项目都由这台服务器提供。
单机处理能力是有限的的,当业务增长到一定程度的时候,单机的硬件资源将无法满足你的业务需求,就出现了集群

集群

当单机处理达到瓶颈的时候,你就将单机复制几份,这样就构成了一个集群。急群众每台服务器就叫做这个集群中的一个节点,所有节点都构成了一个集群,都提供一样的服务,这样处理能力就提高了好几倍。
但是,这个时候就会面临一个问题:用户的请求究竟由哪个节点来处理,最好是让负载娇小的节点来处理,这样是每个节点的压力都比较平均。要实现这个功能就需要在所有节点的前面,增加一个调度者,将所有请求都发给他由他来分配,这个调度者就叫负载均衡服务器。
当业务发展到一定阶段的时候你就会发现一个问题,无论怎样增加节点,整个几群的性能提升已将不是那么明显了,所以就需要有微服务了

分布式

分布式节后就是将一个完整的系统,按照业务能力功能,拆分成一个个独立的子系统。
假如开发一个商城系统,按照微服务的向,我们需要按照工嗯呢该模块拆分成多个独立的服务。如:用户服务,产品服务,订单和售后等。这些服务都是一个个独立的项目,可以独立运行
分布式的优势
系统之间的耦合度大大降低,可以独立开发,独立部署,独立测试,系统与系统之间的便捷非常明确,排错也变得相当容易,开发效率大大提升。

练习

from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.settings import api_settings
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.authentication import jwt_decode_handler
import jwt
from rest_framework import exceptions
class ASBaseAuthentication(JSONWebTokenAuthentication):
    def authenticate(self,request):
        jwt_value = self.get_jwt_value(request)
        # jwt_value = request.GET.get('token')
        print(jwt_value)
        if jwt_value is None:
            return None
        try:
            payload = jwt_decode_handler(jwt_value)
            # user = models.UserInfo(id=payload['user_id'])
        except jwt.ExpiredSignature:
            raise exceptions.AuthenticationFailed('token过期')
        except jwt.DecodeError:
            raise exceptions.AuthenticationFailed('签名错误')
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed('反正就是不对,不让你过怎么了')
        user = self.authenticate_credentials(payload)
        return (user,jwt_value)
posted @ 2022-10-12 23:30  Joseph-bright  阅读(139)  评论(0编辑  收藏  举报