drf day10

一、cookie、session、token介绍

https://www.cnblogs.com/liuqingzheng/p/8990027.html

  1、token:三段式

   第一段::公司信息,加密方式....{ }

    第二段:荷载:真正的数据 {name:lqz,id:1}

    第三段:签名,通过第一段和第二段,通过某种加密方式加密得到的随机字符串 如:aafasdfas

  2、token的使用分两个阶段

    -登录成功后的【签发token阶段】——>生成第三段

     -登录成功访问某个接口的【验证阶段】——>验证token是否合法

 

  -cookie是:存在客户端浏览器的键值对

  -session是:存在于服务端的键值对

  -token是:三段式,它是服务端生成的,存放在客户端内(浏览器就放在cookie中,移动端:存在移动端中)

  

  使用token的认证机制,服务端还要存数据吗?token是服务的生成,客户端来保存,服务端不存储token

 

二、jwt原理介绍

  1、JWT认证

    在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用session认证机制,而是用Json Web Token(本质就是token)认证机制

  2、构成和工作原理

    JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

    第一部分我们称它为头部(header),第二部分我们称其为载荷(payload,类似于飞机上承载的物品),第三部分是签证(signature)

    -header:头

      -声明类型,这里是jwt

      -声明加密的算法:通常直接使用   HMAC、SHA256

      -公司信息

      由:    

    {
          'typ': 'JWT',
          'alg': 'HS256'
        }

     变成了(base64的编码)

       eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

     -payload:荷载

        exp:jwt的过期时间,这个过期时间必须大于签发时间

         iat:jwt的签发时间

        用户信息:用户信息

        由:

{
          "exp": "1234567890",
          "name": "John Doe",
          "userid": 3
        }

        变成了(base64的编码)

         eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

    - signature:签名

      把头和荷载加密后得到的:TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

 

    注意:secret(就是盐,其实也就是密钥)是保存在服务器端的(加密方式+盐),jwt的签发生成,也是服务器端的,secret就是用来进行jwt的签发和jwt的验证,

      所以,他就是你服务端的私钥,在任何场景都不应该流露出去,一旦客户端得知这个secret,那就意味着客户端是可以自我签发jwt了,也就是不安全了

 

总结:

  jwt使用流程最核心的是:

   -签发:登录接口签发

   -认证:认证类认证

三、base64编码和解码

 -1、base64 可以把字符串编码成base64的编码格式:(大小写字母,数字和 =)

    eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogImxxeiIsICJhZG1pbiI6IHRydWV9

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

  -3、应用场景:

      - jwt 中使用

      - 网络中传输字符串就可以使用base64编码

      - 网络中传输图片,也可能适用base64的编码

   -4、编码解码

   -5、把图片保存起来看看

import json
        import base64
        d = {'name': 'lqz', 'userid': 6, 'age': 19}
        info = json.dumps(d)
        print(info)
        # 把字符串使用base64编码
        res=base64.b64encode(info.encode('utf-8'))
        print(res)  # eyJuYW1lIjogImxxeiIsICJ1c2VyaWQiOiA2LCAiYWdlIjogMTl9


        res=base64.b64decode(s)
        with open('code.png','wb') as f:
            f.write(res)

 四、def-jwt快速使用

   1、jwt:签发(登录接口)认证(认证类)

   2、django中使用 jwt

    - 可以自己写

      -https://github.com/jpadilla/django-rest-framework-jwt            比较老

      -https://github.com/jazzband/djangorestframework-simplejwt  比较新

   3、安装

    pip3 install djangorestframework -jwt 

    4、快速使用

     - 迁移表,因为它默认使用auth的user表签发token

     - 创建超级用户(auth的user表中要有记录)

     - 咱们不需要写登录接口了,如果是使用auth的user表作为用户表,它可以快速签发

     - 签发(登录):只需要在路由中匹配(因为它帮咱们写好登录接口了)      

         from rest_framework_jwt.views import obtain_jwt_token
            urlpatterns = [
                path('login/', obtain_jwt_token),
            ]

     - 认证(认证类):导入,配置在视图类上

            class TestView(APIView):
                        authentication_classes = [JSONWebTokenAuthentication,]
                        permission_classes = [IsAuthenticated,]

     - 前端访问时,token需要放在请求头中

            Authorization:jwt token串

 

五、def-jwt修改返回格式

 1、登录成功后,前段看到的格式,太固定了,只有token,我们想做成 {code:100,msg:'登录成功’,token:afjhshjho}

  2、固定写法:写一个函数,函数返回什么,前端就看到什么,配置在配置文件中

  3、使用步骤

    -1 写一个函数
    def jwt_response_payload_handler(token, user=None, request=None):
        return {
            'code':100,
            'msg':'登录成功',
            'username':user.username,
            'token':token
        }
     -2 把函数配置在配置文件中
        JWT_AUTH={
        'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.response.jwt_response_payload_handler',
    	}
        
 # 以后登录接口返回的格式就是咱们写的函数的返回值

  

六、自定义user表,签发token

# models.py 中定义UserInfo表

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

# 写一个登录接口
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=UserInfo.objects.get(username=username,password=password)
            # 根据user,签发token---》三部分:头,荷载,签名
            # 使用djagnorestframework-jwt模块提供的签发token的函数,生成token
            payload = jwt_payload_handler(user) # 通过user对象---》{username:lqz,id:1,过期时间}
            token=jwt_encode_handler(payload) # 根据payload---》得到token:头.荷载.签名
            print(payload)
            print(token)

            return Response({'code':100,'msg':'登录成功','token':token})
        except Exception as e:
            raise APIException('用户名或密码错误')

作业:

1、快速签发

url.py

from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', obtain_jwt_token),
]

2、修改返回格式

views.py

from django.shortcuts import render
from rest_framework.views import APIView
# Create your views here.
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated


class UserView(APIView):
    authentication_classes = [JSONWebTokenAuthentication, ]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response('ok')

jwt_response.py

from rest_framework_jwt.utils import jwt_response_payload_handler


def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'code': 100,
        'msg': '登录错误',
        'username': user.username,
        'token': token
    }

settings.py


JWT_AUTH={
    'JWT_RESPONSE_PAYLOAD_HANDLER' :'app01.jwt_response.jwt_response_payload_handler',
}

3、自定义用户表签发token

views.py

from django.shortcuts import render
from rest_framework.views import APIView
# Create your views here.
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.exceptions import APIException
from .models import User
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class UserView(APIView):
    def post(self, request):
        try:
            username = request.data.get('username')
            password = request.data.get('password')
            gender = request.data.get('gender')
            address = request.data.get('address')
            user = User.objects.get(username=username, password=password, gender=gender, address=address)
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        except Exception as e:
            raise APIException('用户名或密码错误')

models.py

from django.db import models


# Create your models here.

class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    gender = models.CharField(max_length=32)
    address = models.CharField(max_length=32)

4、自定义认证类,验证token


import jwt

from rest_framework import exceptions
from rest_framework.authentication import (BaseAuthentication, get_authorization_header)
from django.utils.translation import ugettext as _
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 .models import User


class MyJSONWebTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        jwt_value = get_authorization_header(request)

        # jwt_value = self.jwt_value(request)
        if jwt_value is None:
            return None
        try:
            payload = jwt_decode_handler(jwt_value)
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()
        username = jwt_get_username_from_payload(payload)
        user = User.objects.filter(username=username).first()

        return user, jwt_value

5.

posted @ 2022-10-12 19:40  W-Y-N  阅读(57)  评论(0)    收藏  举报