cookie,session,token介绍

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

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

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

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

token:三段式

第一段
	头:公司信息,加密方式。。。	{}
第二段
	荷载:真正的数据 {name:lqz,id:1}
第三段
	签名,通过第一段和第二段,通过某种加密方式加密得到的  aafasdfas
  • token的使用分两个阶段
    • 登录成功后的【签发token阶段】--->生成三段
    • 登录成功访问某个接口的 【验证阶段】--->验证token是否合法

JWT原理介绍

Json web token (JWT), token的应用于web方向的称之为jwt

  • 构成和工作原理

    • JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串 就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
  • 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:签名
把头(header)和荷载(payload)加密后得到的
	TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意

ecret是保存在服务器端的(加密方式+盐),jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了
  • jwt使用流程最核心的是
    • 签发:登录接口签发
    • 认证:认证类认证

base64编码与解码

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

应用场景
  • jwt中使用
  • 网络中传输字符串就可以使用base64编码
  • 网络中传输图片,也可能使用base64的编码
编码
import json
import base64

d = {'name': 'joker', 'age': 18}
info = json.dumps(d)
print(info)  # {"name": "joker", "age": 18}
res = base64.b64encode(info.encode('utf8'))
print(res)  # b'eyJuYW1lIjogImpva2VyIiwgImFnZSI6IDE4fQ=='
解码
import base64

s = b'eyJuYW1lIjogImpva2VyIiwgImFnZSI6IDE4fQ=='
res = base64.b64decode(s)
print(res)  # {"name": "joker", "age": 18}

drf-jwt快速使用

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

django中使用jwt 可以自己写

安装

pip3 install djangorestframework-jwt

快速使用

1.迁移表,因为它默认使用auth的user表签发token
2.创建超级用户(auth的user表中要右记录)
3.咱们不需要写登录接口了,如果是使用auth的user表作为用户表,它可以快速签发

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

from rest_framework_jwt.views import obtain_jwt_token

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

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

from rest_framework.permissions import IsAuthenticated

from rest_framework_jwt.authentication import JSONWebTokenAuthentication

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

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

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

Authorization:jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imphc29uIiwiZXhwIjoxNjY1NTYyMzkyfQ.3Xawf3tA-XGzTjUrXysKhWGt9HiRo8UE9iwuCrgOzew

image

drf-jwt修改返回格式

登录成功后,前端看到的格式,太固定了,只有token

{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imphc29uIiwiZXhwIjoxNjY1NTYyMzkyfQ.3Xawf3tA-XGzTjUrXysKhWGt9HiRo8UE9iwuCrgOzew"}

我们想做成这样的

{
    "code": 100,
    "msg": "登录成功",
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imphc29uIiwiZXhwIjoxNjY1NTYyMzkyfQ.3Xawf3tA-XGzTjUrXysKhWGt9HiRo8UE9iwuCrgOzew"
}

需要自己写一个函数

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

把函数配置在配置文件中

以后登录接口返回的格式就是咱们写的函数的返回值

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:头.荷载.签名

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

自定义认证类

from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.settings import api_settings
from rest_framework import exceptions
import jwt

jwt_decode_handler = api_settings.JWT_DECODE_HANDLER

class JwtAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        token = request.META.get('HTTP_AUTHORIZATION')
        # token = token[4:]
        # print(token)
        if token:
            try:
                payload = jwt_decode_handler(token)
                print(payload)
            except jwt.ExpiredSignature:
                msg = '签名过期.'
                raise exceptions.AuthenticationFailed(msg)
            except jwt.DecodeError:
                msg = '签名错误.'
                raise exceptions.AuthenticationFailed(msg)
            except jwt.InvalidTokenError:
                raise exceptions.AuthenticationFailed()

            # user = self.authenticate_credentials(payload)  # 配合权限类使用
            user = UserInfo.objects.filter(pk=payload.get('user_id')).first()  # 不能配合权限类使用

            return user, token

        else:
            raise exceptions.AuthenticationFailed('Authorization不能为空')

配置JWT时间

JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.jwt.jwt_response_payload_handler',
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),  # JWT过期时间

}

'''
    days: 天
    seconds: 秒
    microseconds: 微秒
    milliseconds: 毫秒
    minutes: 分钟
    hours: 小时
    weeks: 周

'''
 posted on 2022-10-12 17:16  Joker_Ly  阅读(481)  评论(0)    收藏  举报