django-jwt

一.认识

认识:

  1. 浏览器访问服务端,服务器根据自己保存的secret_key生成token,返回给浏览器(这个secret_key默认使用settings.py中的secret_key)
  2. 浏览器再次访问服务器带着后台返回的token,服务器根据secret_key对token前两段内容进行加密生成第三段内容和前端第三段内容进行比较,相同就可以,再一个就是取出前端的第二段内容进行过期验证

1.jwt构成

jwt就是一段字符串,三段信息构成,如下:

u23o1u4hfkadhglahwbkjfsdjlsgjaljg.fsdjkjrlj4l2j4l2j3lk4jlfnasjgbajskhgahghi2q42o134.ou4o24j2o424j2ofow
1.header

jwt的头部有两部分信息(此处不要存储敏感信息):

  • 声明类型
  • 声明算法,通常使用HMAC SHA256

完整头部如下:

{
    'typ': 'JWT',  #csrf也是一种类型,这里是固定的
    'alt':'HS256'  #生成签证时使用
}

将头部进行base64.bs4endcode()加密(该加密是对称的,可解密),构成第一部分

u23o1u4hfkadhglahwbkjfsdjlsgjaljg
2.payload

载荷就是存放有效信息的地方:

  • 标准中注册的声明
  • 公共声明
  • 私有声明

标准中注册的声明(建议但不强制使用):

  • iss:jwt签发者
  • sub:jwt所面向的用户
  • aud:接收jwt的一方
  • exp:jwt的过期时间,这个过期时间必须大于签发时间
  • iat:jwt的签发时间
  • jti:jwt的唯一身份标识,用来作为一次性token,从而回避攻击

公共的声明:公共声明可添加任何信息

定义一个payload,json格式的数据

{
    "sub":"1234123412",
    "exp":"4214124", #时间戳格式
    "name":"John Doe",
}
3.signature

JWT的第三部分是一个签证信息,由三部分构成(这部分用来校验token有效性):

  • header(base64之后的)
  • payload(base64之后的)
  • secret密钥

这部分需要base64加密后的header和payload,然后加上secret组合加密,构成了JWT的第三部分

二.drf应用

1.安装

pip install djangorestframework-jwt

2.配置

import datetime
# drf框架的配置信息
REST_FRAMEWORK = {
    # 设置所有接口都需要被验证
    'DEFAULT_PERMISSION_CLASSES': (
        #’rest_framework.permissions.IsAuthenticatedOrReadOnly’,
    ),
    # 用户登陆认证方式
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

# jwt载荷中的有效期设置
JWT_AUTH = {
    #token 有效期
    'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=8),
    #是否验证token有效期
    'JWT_ALLOW_REFRESH': True, 
     #续期有效期(该设置可在24小时内带未失效的token 进行续期) 
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(hours=24),
    # 自定义返回格式,需要手工创建,默认的只会返回token
    'JWT_RESPONSE_PAYLOAD_HANDLER': ‘Users.utils.jwt_response_payload_handler’,
}

AUTH_USER_MODEL = "users.UserInfo"

#JWT_EXPIRATION_DELTA和JWT_REFRESH_EXPIRATION_DELTA:在django中,如果token在设置的8hour之内进行token刷新,是没什么问题的,但一旦过了8hour,再刷新token也没用,此时就需要前端跳到登录界面重新登录,因此JWT_REFRESH_EXPIRATION_DELTA并没有多大用处

自定义返回格式(在app(Users)下新建utils.py)

def jwt_response_payload_handler(token, user=None, request=None):
    """
    自定义jwt认证成功返回数据
    """
    return {
        'token': token,
        'id': user.id,
        'username': user.username
    }

models.py

from django.db import models

# Create your models here.

from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    name = models.CharField(max_length=20)
    tel = models.CharField(max_length=20)
#创建完成后
#1.python manage.py makemigrations  && migrate
#2.python manage.py createsuperuser会在UserInfo表中生成一条记录,因为setting.py中指定了AUTH_USER_MODEL

urls.py

from django.conf.urls import url
from rest_framework_jwt.views import obtain_jwt_token,refresh_jwt_token,verify_jwt_token
urlpatterns = [
    url(r'^login/',obtain_jwt_token),
    url(r'^verify/',verify_jwt_token),  #校验token有效性
    url(r'^refresh/',refresh_jwt_token) #刷新并返回新的token
]

#前端发来post的json请求,须指定键值对{"username":"xx","password":"xx"},obtain_jwt_token会默认从AUTH_USER_MODEL对应的表中查询数据,如果正确匹配,则返回token值,如果不正确,返回400错误
#refresh_jwt_token是验证并刷新token,如果发来的token有效,则生成新的token并返回给前端,否则返回400错误。

login.vue:登录界面,登录成功后获取token并存入sessionstorage|localstorage

axios({
  method: "post",
  url: this.$setting.HTTP + "users/login/", 
  headers: {
    "Content-Type": "multipart/form-data"
  },
  withCredentials: true,
  data: formdata
})
  .then(res => {
    // console.log(res.data.token);
    sessionStorage.setItem("token", res.data.token);
    this.$router.push("/base/showCenter");
  })
  .catch(function(error) {
    // this.$message.error('错了哦,这是一条错误消息');
  });

index.vue:是登录后跳转的界面,每次进入这个界面都要判断是否有token以及token是否校验成功,如果没有token,返回登录界面,如果有,再发送到后台去验证

created(){
            let thiss = this;
            let token = sessionStorage.getItem("token");
            //判断本地是否存在token
            if (token){
                //如果存在token,还需要去后台校验token是否有效
                axios({
                    method:"post",
                    //超过JWT_EXPIRATION_DELTA设置的时间后返回400错误
                    url: this.$setting.HTTP + "users/refresh/",
                    data:{"token":token},
                }).then((res)=>{
                    console.log(res);
                    //sessionStorage.setItem("token",res.data.token)
                }).catch(function (error) {
                    thiss.$router.push("/")
                })
            }else {
                thiss.$router.push('/login')
            }

3.drf中验证

以上没有用到drf,只是默认的前后端交互的一些配置。当我们访问某个接口时,需要在headers带上token,后端验证

from django.shortcuts import render
from rest_framework.generics import ListAPIView
from host import models,utils
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


# Create your views here.

class ListView(ListAPIView):
    authentication_classes = [JSONWebTokenAuthentication,] //验证前端header中携带的token
    queryset = models.Host.objects.filter(id=1)
    serializer_class = utils.HostSerializer

postman中headers中携带固定键值对{"Authorization":"JWT xxxxxxxx"},注意JWT和token以空格隔开

三.坑理解

https://www.jianshu.com/p/a60efb8bac35

posted @ 2023-02-26 16:23  MISF  阅读(156)  评论(0编辑  收藏  举报
     JS过度和变形效果演示   
  
    html5.png