vue+django的JWT验证

1、配置JWT和跨域请求

vue和django的请求是跨域请求, 因此要配置跨域请求

在settings.py中添加如下代码

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "app01.apps.App01Config",
    'corsheaders', #允许跨域访问之1--它是 Django REST framework 的一个扩展,它提供了一种简单的方式来处理跨域资源共享(CORS)问题
    'rest_framework',#JWT之1--引入rest_framework,rest_framework是Django框架中的一个扩展包,能够帮助开发者简化RESTful API的开发过程,提高开发效率。
    'rest_framework_simplejwt',#JWT之2--是 Django REST framework 的一个扩展,它提供了 JWT 认证的功能
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    'corsheaders.middleware.CorsMiddleware',  #允许跨域访问之2--它是 Django REST framework 的 corsheaders 扩展中的一个中间件

]


from datetime import timedelta
#允许跨域访问之3--域名白名单
CORS_ALLOWED_ORIGINS = [  
    "http://localhost:5173",  # Vue应用的地址,注意要和自己的项目对应有的人端口是8080 
]  

#JWT之3--配置JWT的参数
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),  # ACCESS_TOKEN的有效期为60分钟
    'REFRESH_TOKEN_LIFETIME': timedelta(days=15),  # REFRESH_TOKEN的有效期为15天
    'ROTATE_REFRESH_TOKENS': False,  # 刷新令牌轮换功能关闭
    'BLACKLIST_AFTER_ROTATION': False,  # 刷新令牌轮换后不会将旧令牌列入黑名单
    'UPDATE_LAST_LOGIN': False,  # 不会更新用户的最后登录时间

    'ALGORITHM': 'HS256',  # 使用HS256算法进行签名
    'SIGNING_KEY': 'suijizifc',  # 签名密钥
    'VERIFYING_KEY': None,  # 验证密钥
    'AUDIENCE': None,  # 受众
    'ISSUER': None,  # 发行者
    'JWK_URL': None,  # JSON Web Key URL
    'LEEWAY': 0,  # 允许的时间偏差

    'AUTH_HEADER_TYPES': ('Bearer',),  # 授权头类型
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',  # 授权头名称
    'USER_ID_FIELD': 'id',  # 用户ID字段
    'USER_ID_CLAIM': 'user_id',  # 用户ID声明
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',  # 用户认证规则

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),  # 授权令牌类
    'TOKEN_TYPE_CLAIM': 'token_type',  # 令牌类型声明
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',  # 令牌用户类

    'JTI_CLAIM': 'jti',  # JWT ID声明

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',  # 滑动令牌刷新过期声明
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),  # 滑动令牌的有效期为5分钟
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),  # 滑动令牌的刷新期为1天,  # End of Selection
}

2、制作带有JWT验证功能的视图

做JWT验证的视图函数,必须封装在类内, 例如我将这个类写在views/imgs_get.py文件里了

函数名称是固定的, 开发者自定义名称的函数不能被直接调用. 如果是get请求,函数名必须为get; 如果是post请求,函数名必须为post

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from app01.models import Imgs
from django.http import JsonResponse

class ImgsGetView(APIView):
    permission_classes = ([IsAuthenticated])#验证access令牌
    
    #这里是get请求,所以函数名必须为get
    def get(self, request):
        imgs=Imgs.objects.all()
        imgs_list=[]
        for img in imgs:
            imgs_list.append({'id':img.id,'img_num':img.img_num,'img_name':img.img_name,'img_time':img.img_time})
        return JsonResponse({'result': 'success', 'message': imgs_list})

由于函数封装在类内,而非普通函数, 所以对应的urls.py的配置也要改变

from app01.views.imgs_get import ImgsGetView#加载视图类
urlpatterns = [
    ...
    path('api/ImgsGet/',ImgsGetView.as_view(),name='ImgsGet'),
    ...
]

对应的Vue的请求方式也要发送变化, 即要携带令牌信息

axios.get('http://127.0.0.1:8000/api/ImgsGet/', {
      headers: {
        'Authorization': 'Bearer ' + 令牌信息
      }
    })

3、令牌信息如何获取呢

在登陆时, 将用户名和密码传给TokenObtainPairView, 这是应该django自带的验证用户信息并返回令牌的类, 我们只需要在urls.py里给这个类指定一个访问链接即可

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair')

 登录并获取令牌,Login.vue

<template>
    <div class="login-container">
      <h1>Login</h1>
      <form @submit.prevent="handleSubmit">
        <label for="username">Username:</label>
        <input id="username" v-model="username" type="text" required>
        <label for="password">Password:</label>
        <input id="password" v-model="password" type="password" required>
  
        <button type="submit">Login</button>
      </form>
    </div>
  </template>

  
  <script setup>
    import axios from 'axios';
    import { ref } from 'vue';
    import router from '@/router';
 
    let username=ref()
    let password=ref()
       
    async function handleSubmit() {
      try {
          //提交登录信息给TokenObtainPairView
          const res = await axios.post('http://127.0.0.1:8000/api/token/', {
          username: username.value,
          password: password.value
        });
  
        
        const { access, refresh } = res.data;
        
        //将获取的JWT存到localstorage里持久化, localStorage相当于一个全局字典, 以后再任何文件里想要存数据都可以使用它,支持跨文件存取,即a文件中存的,b文件中可以读
        //存储数据: localStorage.setItem('数据名', 数据值);
        //读取数据: localStorage.getItem('数据名');
        localStorage.setItem('access', access);//access令牌
        localStorage.setItem('refresh', refresh);//refresh令牌, 其他功能的令牌,本次用不到,暂不展开
        
        localStorage.setItem('username', username.value);
  
  
        router.push('/home/video');
      } catch (error) {
        console.log('登陆失败的返回:', error);
        alert('登陆失败的返回:'+error);
        
      }
    }
  
 
  </script>
  
  <style scoped>
  </style>

 

4、携带access令牌请求

axios.get('http://127.0.0.1:8000/api/ImgsGet/', {
      headers: {
        'Authorization': 'Bearer ' + localStorage.getItem('access')#携带access令牌信息
      }
    })

 在access令牌里, 是包含了用户信息的, 比如用户id, 在携带令牌请求时, django会自动解析请求中的JWT令牌,并将用户信息添加到request对象中。因此我们可以通过request.user来访问这个用户信息, 比如

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from django.http import JsonResponse

from django.contrib.auth.models import User
# from icecream import ic

class BandEmailView(APIView):
    permission_classes = ([IsAuthenticated])

    #这里是post请求,函数名必须为post
    def post(self, request):
        if request.method == 'POST':
            email = request.POST.get('email')
            
            #django会自动解析请求中的JWT令牌,并将用户信息添加到request对象中。因此我们可以通过request.user来访问这个用户信息
            user_id = request.user.id#获取用户id
            print('user_id',user_id)

            user = User.objects.filter(id=user_id).first()
            user.email = email
            user.save()
            return JsonResponse({'result': 'success'})
        
        return JsonResponse({'result': 'error'})

小技巧

如果觉得每次请求都要写令牌信息太麻烦,可以将请求封装一下,如我在vue-project/public/js/myjs.js里封装了应该axios请求

const instance = axios.create({
    baseURL: 'http://127.0.0.1:8000',
    timeout: 1000,
    headers: {
        'Authorization': `Bearer ${localStorage.getItem('access')}`
    }
 })

以后请求时直接使用 instance

instance.get('http://127.0.0.1:8000/api/ImgsGet/')

 

posted @ 2024-04-15 01:55  台友涛  阅读(5)  评论(0编辑  收藏  举报