当前位置: 首页 > news >正文

vue3实现登录获取token并自动刷新token进行JWT认证

在《django应用JWT(JSON Web Token)实战》介绍了如何通过django实现JWT,并以一个具体API接口实例的调用来说明JWT如何使用。本文介绍如何通过vue3的前端应用来使用JWT认证调用后端的API接口,实现一下的登录认证获取JWT进行接口认证。

在这里插入图片描述

一、账号密码登录获取JWT

通过Login.vue实现登录的用户名、密码表单信息收集,调用getToken()方法进行鉴权验证并获取jwt的token。
Login.vue

<template><div class="body"><el-form :model="form" :rules="rules" ref="loginForm" class="loginContainer"><h3 class="loginTitle">欢迎登录</h3><el-form-item label="用户名" prop="username" :label-width="formLabelWidth"> <el-input type="text" v-model="form.username" placeholder="请输入用户名"></el-input></el-form-item><el-form-item label="密码"  prop="password" :label-width="formLabelWidth"> <el-input type="password" v-model="form.password" placeholder="请输入密码"></el-input></el-form-item><el-form-item :label-width="formLabelWidth"> <el-button type="primary" :plain="true" @click="submitForm('form')">登录</el-button></el-form-item></el-form></div>
</template><script>
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus';
import {getToken} from '../api/user'
export default {data() {return {form: {username: '',password: '',err_username: "",err_password: "",},rules: {username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],password: [{ required: true, min:6, message: '请输入密码', trigger: 'blur' }]},     formLabelWidth: '120px'};},methods: {submitForm(formName) {if (this.$refs.loginForm) {this.$refs.loginForm.validate(valid => {if (valid) {// 提交表单逻辑console.log('提交成功:', this.form);this.login();} else {console.log('验证失败');ElMessage.error('验证失败,请检查您的输入!');}});} else {console.error('表单未找到');}},login() {var that = this;this.message = "";// 用户名密码鉴权获取jwt的tokengetToken({'username': this.form.username,'password': this.form.password,}).then((Response) => {console.log(Response);if (Response && Response.access) {// //保存数据到本地存储this.username= that.form.username;useUserStore().login(this.username,Response.access,Response.refresh)this.username = "";this.password = "";this.$router.push({name:"home"}); //跳转到首页}}).catch(function (error) {console.log(error);if ("username" in error) {that.err_username = error.username[0];} else if ("password" in error) {that.err_password = error.password[0];} else {ElMessage.error('登录失败!');}});},}
};
</script><style scoped>.loginContainer{border-radius: 15px;background-clip: padding-box;text-align: left;margin: auto;margin-top: 180px;width: 450px;padding: 15px 35px 15px 35px;background: aliceblue;border:1px solid blueviolet;box-shadow: 0 0 25px #f885ff;}.loginTitle{margin: 0px auto 48px auto;text-align: center;font-size: 40px;}.loginRemember{text-align: left;margin: 0px 0px 15px 0px;}.loginbody{width: 100vw;height: 100vh;background-size:100%;overflow: hidden;}
</style>

在登录时调用getToken()方法获取jwt的token
getToken的封装方法如下:

import request from '@/utils/request'export function getToken(data) {return request({url: 'token/',method: 'post',data})}

通过用户名和密码鉴权可以获得JWT的token,接口会返回access的token和refresh的token,需要将这两个token保存下来,access的token用来进行API接口的jwt认证,refresh的token用来刷新失效的access的token。

二、将JWT保存至本地

通过pinia将token保存至浏览器的本地存储,以便于后面请求API时带上访问的token

import { defineStore } from 'pinia'
import { refreshToken } from '../api/user'export const useUserStore = defineStore('user', {persist: {enabled: true, //开启数据持久化strategies: [{key: "userState", //给一个要保存的名称storage: localStorage, //sessionStorage / localStorage 存储方式},],},state: () => ({isLoggedIn: false,username: '',jwtAccessToken: null,jwtRefreshToken: null,}),actions: {login(username, accessToken,refreshToken) {this.username = usernamethis.isLoggedIn = truethis.setToken(accessToken, refreshToken)},logout() {this.username = ''this.jwtAccessToken = nullthis.isLoggedIn = false},setToken(accessToken, refreshToken) {this.jwtAccessToken = accessTokenthis.jwtRefreshToken = refreshToken},refreshToken() {return new Promise((resolve, reject) => {refreshToken({"refresh":this.jwtRefreshToken}).then((response) => {this.setToken(response.access, this.jwtRefreshToken)resolve(response.access)console.log('return refreshToken-----------'+response.access)}).catch((error) => {reject(error)})})}},getters: {getIsLoggedIn: (state) => state.isLoggedIn,getUsername: (state) => state.username,getUserAccessToken: (state) => state.jwtAccessToken,getRefreshToken: (state) => state.jwtRefreshToken,}
})

在登录的Login.vue组件中调用useUserStore().login(this.username,Response.access,Response.refresh)将用户名、access的token、refresh的token保存至浏览器的本地存储。

三、请求API带上JWT

将axios的调用封装成request.js在调用API接口时带上JWT

import axios from 'axios'
import Router from '@/components/tools/Router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import { refreshToken } from '../api/user'const api_rul = import.meta.env.VITE_APP_API_URL// create an axios instance
const service = axios.create({baseURL: api_rul,timeout: 5000, // request timeout
})// request interceptor
service.interceptors.request.use(config => {// do something before request is sentconst { url } = config// 指定页面访问需要JWT认证。if (url.indexOf('/login')!== -1) {return config}let jwt = useUserStore().getUserAccessTokenconfig.headers.Authorization = `Bearer ${jwt}`return config},error => {// do something with request errorconsole.log(error) // for debugreturn Promise.reject(error)}
)export default service

主要是在请求头重带着jwt的信息

let jwt = useUserStore().getUserAccessToken
config.headers.Authorization = `Bearer ${jwt}`

四、在token失效时自动重新获取token

前面提到JWT基于安全考虑有两个token,一个是access token ,一个是refresh token 。access token的失效时间较短,可以有效降低泄露而造成的影响,两个token的区别和作用如下:

access tokenrefresh token
有效时间较短(如半小时)较长(如一天)
作用鉴权验证重新获取access token
什么时候使用每次接口鉴权验证时access token失效时使用

使用refresh token的逻辑如下:
在这里插入图片描述

以下通过拦截器实现token失效后重新获取access token

import axios from 'axios'
import Router from '@/components/tools/Router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import { refreshToken } from '../api/user'const api_rul = import.meta.env.VITE_APP_API_URL// create an axios instance
const service = axios.create({baseURL: api_rul,timeout: 5000, // request timeout
})// request interceptor
service.interceptors.request.use(config => {// do something before request is sentconst { url } = config// 指定页面访问需要JWT认证。if (url.indexOf('/login')!== -1) {return config}let jwt = useUserStore().getUserAccessTokenconfig.headers.Authorization = `Bearer ${jwt}`return config},error => {// do something with request errorconsole.log(error) // for debugreturn Promise.reject(error)}
)// response interceptor
service.interceptors.response.use(response => {const res = response.datareturn res},async error => {console.log('err' + error) // for debugconst originalRequest = error.config;// 授权验证失败if (error.response.status === 401 && originalRequest._retry!== true) {originalRequest._retry = true;// 刷新tokenlet jwtRefreshToken=useUserStore().getRefreshTokenawait refreshToken({"refresh":jwtRefreshToken}).then((response) => {// 刷新token成功,重新请求let jwtToken=response.accessuseUserStore().setToken(jwtToken, jwtRefreshToken)console.log('return refreshToken-----------'+response.access)originalRequest.headers.Authorization = `Bearer ${jwtToken}`return service(originalRequest)                }).catch((error) => {// 刷新token失败,跳转到登录页面ElMessage.error('请重新登录!')Router.push({name:'login'})})}// 内部错误if (error.response.status === 500) {let errormsg=error.response.data.msgElMessage.error('服务器内部错误!'+errormsg)}if (error.response.status === 400){ElMessage.error('错误的请求!')}return Promise.reject(error)}
)export default service

在判断error.response.status === 401时调用refreshToken重新获取jwttoken进行接口的调用。


博客地址:http://xiejava.ishareread.com/


http://www.mrgr.cn/news/46983.html

相关文章:

  • 面试指南1009
  • mysql模糊查询优化
  • 数通--3
  • linux通过网络scp传文件
  • 2024最新版:大厂AI大模型面试题集锦及详解,非常详细收藏我这一篇就够了
  • 仿IOS桌面悬浮球(支持拖拽、自动吸附、自动改变透明度与点击、兼容PC端与移动端)
  • Umi中的微前端
  • 如何做好乡村文化传承与乡村经济发展
  • mmap和ioremmap解析
  • 揭秘地表水与地下水耦合的奥秘!基于QSWATMOD的SWAT-MODFLOW模拟
  • centos6.9不用安装光盘在控制台重置root密码
  • 安全工具 | 搭建带有 Web 仪表板的Interact.sh
  • 如何确保我的Java爬虫在获取Lazada商品详情时遵守API使用限制?
  • 前端的全栈之路:基于 Vue3 + Nest.js 全栈开发的后台应用
  • 美国亚马逊灯串UL588测试报告测试哪些内容
  • 知识付费对企业的帮助 知识付费的优势 知识服务服务 企业为什么一定要做知识付费
  • 【数据库】MySQL解决ONLY_FULL_GROUP_BY模式
  • 刷题 双指针 滑动窗口
  • 你能描述一下Java中的JDBC连接池吗?Java中的事务隔离级别有哪些?它们分别是什么?
  • 三菱FX5U-CCLINK IEFB网关HT3S-CIS-MDN读取七星华创CS310空气流量计数据应用案例