位置: IT常识 - 正文

Vue3入门笔记----登录功能

编辑:rootadmin
Vue3入门笔记----登录功能 文章目录登录功能介绍axios请求API和axios的封装jwt的介绍和在登录功能中的应用vue3中api的集中管理登录页面的实现通过vuex管理token(状态管理)路由守卫思考题

推荐整理分享Vue3入门笔记----登录功能,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

这个系列的笔记重点会放在怎么样利用Vue3把项目架设起来并跟后端API互动,不会介绍Vue的基础特性,关于Vue的基础特性可以参考这个视频四个小时带你快速入门Vue,我是看这个入门的,觉得还不错。

代码地址: https://github.com/yexia553/vue_study/tree/%E9%85%8D%E7%BD%AEvue-router/vue3-notes

这篇笔记的内容有点难,建议多看几遍

笔记中的代码一定要结合github仓库的内容和博客中提到的视频一起看,不然不太容易看懂

这篇笔记中新使用了好几个第三方包,建议新手在看博客内容之前现在项目根目录下执行以下cnpm install 安装这些依赖,以免后面报错

同步发表于个人站点: http://panzhixiang.cn/article/2022/11/15/61.html

登录功能介绍

很多网站都有登录功能,访问者在页面上输入账号密码之后页面会请求后端API进行认证,如果认证通过会跳转到首页。我们简单地来拆分一下这个过程中具体有那几件事情。

首先要有一个登录页面让访问者输入账号密码,并且要有登录按钮后端要有一个认证相关的API用来给页面调用以检查访问者提供的账号密码是否正确上一步的认证检查通过之后,前端会获得一个token,这个token标志着访问者是合法的,需要把这个token存储起来,以便在后面请求后端的时候使用

以上就是实现一个登录功能大致的过程。在这个过程中会用到axios来调用API,另外后端的认证用的jwt,还需要vuex来做状态管理,我会在下面分别介绍这三个知识点。

axios请求API和axios的封装

做前端开发的人肯定听说过axios,关于axios的介绍我就不写了,网上有很多相关的内容。

原生的axios在调用API的时候每一次都要写很多代码,我做了一点封装,代码放在src/api/request.js中,

import axios from 'axios'import config from './config.js'import Cookies from 'js-cookie'import { ElMessage } from 'element-plus'import store from '../store/index.js'import { useRouter } from 'vue-router';const NETWORK_ERROR = '网络请求错误,请稍后重试...'const service = axios.create({ baseURL: config.baseApi,})service.interceptors.request.use((req) => { //可以在请求之前做一些事情 //比如自定义header, jwt-token等等 return req})service.interceptors.response.use((res) => { // 对请求得到的响应做一些处理 if (res.status === 200) { // 状态码是200表明请求正常,可以返回请求到的数据也可以做一些其他事情 return res } else { // 状态码不是200说明请求可能出错 // ElMessage.error(NETWORK_ERROR) // return Promise.reject(NETWORK_ERROR) // 这里的封装不完善,直接抛出异常会导致页面不能正常提醒用户,先这样返回,以后修改 return res }})let tokenRefresher = async () => { let router = useRouter() let now = new Date().getTime() if (now - Cookies.get('last_token_refresh_time') > 1000 * 60 * 4) { let res = await service({ url: '/api/token/refresh/', method: 'post', headers: { 'Authorization': `Bearer ${Cookies.get('access_token')}` }, data: { refresh: `${Cookies.get('refresh_token')}` } }) if (res.status === 200) { store.commit('setAccessToken', res.data.access) } else if (res.status === 403) { // refresh token过期了,要求重新登录 store.commit('clearRefreshToken') store.commit('clearAccessToken') router.push({ name: 'login' }) } }}function request(options) { options.method = options.method || 'get' // 如果没有传入method这个参数,就默认是get请求 if (options.method.toLowerCase() === 'get') { // console.log(options) options.params = options.data } // 如果可以从cookie中获取到access_token,就添加到header中 if (Cookies.get('access_token')) { // 设置token之前先检查是否需要更新token tokenRefresher() service.defaults.headers.common['Authorization'] = `Bearer ${Cookies.get('access_token')}` } return service(options)}export default request

其实这一部分封装的不好,几乎没什么额外的功能,但是整个封装的思路都在里面了,强烈建议结合Vue3中如何封装axios 这个视频一起理解axios封装的部分,在实际工作中还是很有用的,在我接触axios封装之前就是在每一次调用的api的时候写一堆重复的代码,修改布置后确实方便很多。

上面这一段代码中的tokenRefresher这个函数是用来更新access token的,暂时可以先不管,等看完后面的jwt和api部分在回头理解这一部分。

jwt的介绍和在登录功能中的应用

在看下面的内容之前,推荐先完整仔细地看一下下面两篇博客:

JSON Web Token 入门教程 ---- 阮一峰JWT 介绍 - Step by Step

可以不用细究里面的细节,了解运行过程即可。

我简单的概括一下jwt在登录这个场景中过程,以便理解后面的内容。

访问者在页面上输入账号密码并点击登录之后前端会请求后端的/api/token/这个api,如果认证通过,后端会给前端返回一个access token和一个refresh tokenaccess token是用来访问后端api的,所以在之后的请求中都要携带这个token才能正常访问api;refresh token是用来刷新access token的,因为一般来说,access token的有效期很多,比如django 的DRF框架中,默认情况下,access token的有效期只有5分钟,但是refresh token的有效期是8个小时前端拿到access token和refresh token 需要找一个地方把它们存储起来,以便后面使用,比如可以存在cookie中,或者是localstorage中等要有一个检查机制,检查access token有没有过期,如果过期了就要及时用refresh token进行更新,获取新的access token,并且还要更新在上一步存存储的access tokenvue3中api的集中管理

在前后端分离的情况下,前端一般都需要一个方法来管理被调用的API,这样比较便于后期的维护、更新和修改等工作,这里介绍一种我比较喜欢的方法,这个方式使用于中小型的前端项目,调用的API不是非常多的情况。

首先在src/api目录下新建一个config.js文件,内容如下,/** * 项目的环境配置 */// 这是vite的一种使用方式:https://cn.vitejs.dev/guide/env-and-mode.html#env-filesconst env = import.meta.env.MDOE || 'dev'const envConfig = { dev: { baseApi: 'http://localhost:8000', }, test: { baseApi: 'test.example.com/api', }, prod: { baseApi: 'example.com/api', }}export default { env, ...envConfig[env]}

不难看出,这个文件是用来做环境管理的,比如第一个dev表示本地的开发环境,test表示线上测试环境,prod表示生产环境,还可以按照自己的需要添加其他的配置。 这个config.js在前面axios的封装中也有用到,大家可以回到上面看一下代码。

然后在src/api目录下创建一个api.js文件,这个文件就是用来放置所有会被调用的api的地方,代码如下,import request from "./request.js";export default { login(params) { return request({ url: '/api/token/', method: 'post', data: params, mock: false }) }, refreshToken(params) { return request({ url: '/api/token/refresh', method: 'post', data: params, mock: false }) }}Vue3入门笔记----登录功能

api.js里面目前只包含两个接口,一个是login,用于在登录的时候调用,一个是refreshtoken,用于刷新access token, 这个在上面jwt部分介绍过。

创建了api.js之后,还需要把它跟vue绑定起来,这样才能调用。 修改src/main.js这个文件,修改后如下,import { createApp } from 'vue'import App from './App.vue'import ElementPlus from 'element-plus'import 'element-plus/dist/index.css'import router from './router/index.js'import * as ElementPlusIconsVue from '@element-plus/icons-vue'import './assets/main.css'import api from './api/api.js'const app = createApp(App)for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component)}app.use(router)app.use(ElementPlus)app.mount('#app')app.config.globalProperties.$api = api

修改的部分就是在import里面引入src/api/api.js;然后在最后一行把api配置到vue的global properties,方便以后引用。

到这里vue中api的集中管理就结束了。

登录页面的实现

上面做了那么多准备工作,都是为了实现登录页面做的,我们现在来实现它。在src/views目录下创建login文件夹,然后在其中创建Login.vue文件,文件内容如下,主要看代码中的注释。

<template> <el-form :model="formData" status-icon class="login-container" ref="formRef"> <h3 class="login-title">登陆</h3> <el-form-item label="用户名" prop="username" label-width="80px"> <el-input type="input" auto-complete="off" placeholder="请输入用户名" v-model="formData.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password" label-width="80px"> <el-input type="password" auto-complete="off" placeholder="请输入密码" v-model="formData.password"></el-input> </el-form-item> <el-form-item class="login-submit"> <!-- 这里通过@click绑定login函数,用于点击的时候触发登录功能 --> <el-button type="primary" class="login-submit" @click="login()">登录</el-button> </el-form-item> </el-form></template><script>import { getCurrentInstance, reactive } from 'vue';import { defineComponent } from 'vue-demi';import { useRouter } from 'vue-router';import { ElMessageBox } from 'element-plus'; //这是用来在账号密码错误时弹窗提示的import store from '../../store/index.js'; //这里引入vuex,暂时先忽略,后面会介绍export default defineComponent({ setup() { const { proxy } = getCurrentInstance() // 注意这里,下面login函数会用到 const router = useRouter() // vue3中获取表单数据需要使用reactive const formData = reactive({ username: '', password: '', }); // 使用异步的方式请求api let login = async () => { let res = await proxy.$api.login(formData) // 通过$api来调用login if (res.status === 200) { // 如果返回码是200表明账号密码正确,校验通过 // 下面两行代码是获取后端返回的access token和refresh token并存储起来,方便后面使用 store.commit('setAccessToken', res.data.access) store.commit('setRefreshToken', res.data.refresh) store.commit('updateLastRefreshTime') // 更新最近一次刷新access token的时间,用于比较access token是否过期,这里要和jwt的内容联系起来看 router.push({ // 跳转到主页面, name: 'main' }) } else { // 如果账号密码错误的话就要进行提示,并且重新回到登录页面 ElMessageBox.alert('账号密码错误,请重试!') router.push({ name: 'login' }) } }; return { formData, login, } }})</script><style lang="less" scoped>.login-container { border-radius: 15px; background-clip: padding-box; margin: 180px auto; width: 350px; padding: 35px 35px 15px 35px; background-color: #fff; border: 1px solid #eaeaea; box-shadow: 0 0 25px #cac6c6;}.login-title { margin: 0px auto 40px auto; text-align: center; color: #505458;}.login-submit { margin: 10px auto 0 auto; justify-content: center;}</style>

上面这一段代码实现了页面登录的样式和功能,但是我们还缺少一个指向这个页面的路由,现在来配置,修改src/router/index.js的内容,修改后如下,

import { createRouter, createWebHashHistory } from 'vue-router'const routes = [ { path: '/', name: 'main', redirect: '/home', component: () => import('../views/Main.vue'), children: [ { path: '/home', name: 'home', component: () => import('../views/home/Home.vue'), }, { path: '/other', name: 'other', component: () => import('../views/other/Other.vue'), }, ] }, { path: '/login', name: 'login', component: () => import('../views/login/Login.vue') }]const router = createRouter({ history: createWebHashHistory(), routes})export default router

其实只修改了一个地方,就是在routes中添加了一个一级路由/login, 用于指向登录页面,这个应该也很好理解。 到这里登录页面相关的内容就完成了,但是整个登录功能还不能正常运行,还缺少一个重要部分,vuex。

通过vuex管理token(状态管理)

上一步在Login.vue这个文件中,我们先是引入了import store from '../../store/index.js' ,然后又是存储access token、refresh token和最后更新access token的时间,但是具体是怎么实现的没有介绍,现在来说一下。

vuex网上也是有很多,我贴两篇感觉写的还不错的博客:

vuex-介绍vuex是什么

大家可以先浏览一下上面这两篇博客,对于vuex有一个整体的了解再继续看下面的内容。

假设大家已经看完了上了上面的两篇博客,我们开始介绍vuex在登录这个场景中应用。

在src/路径下创建store文件夹,然后在里面穿件index.js文件,文件内容如下,

import { createStore } from 'vuex' // 引入createStore, 这里跟vue2不一样import Cookies from "js-cookie"export default createStore({ state: { // state里面定义了一些要使用的变量 access_token: '', refresh_token: '', last_token_refresh_time: new Date("October 01, 1975 00:00:00"), // 以1975-10-01 00:00:00 为初始值 }, mutations: { // mutations里面主要是针对state里面的变量进行一些操作的函数, // 在登录这个场景中,分别对access token和refresh token有设置(set)、清除(clear)和获取(get)3个操作,一共6个 // 额外还有一个更新access token的函数 // access token 和 refresh token 我们是存储在cookie中,这个很简单,看代码就能理解了,想要深入了解的需要自行搜索 setAccessToken(state, val) { state.access_token = val Cookies.set('access_token', val) }, clearAccessToken(state) { state.access_token = '' Cookies.remove('access_token') }, getAccessToken(state) { state.access_token = state.access_token || Cookies.get('access_token') }, setRefreshToken(state, val) { state.refresh_token = val Cookies.set('refresh_token', val) }, clearRefreshToken(state) { state.refresh_token = '' Cookies.remove('refresh_token') }, getRefreshToken(state) { state.refresh_token = state.refresh_token || Cookies.get('refresh_token') }, updateLastRefreshTime(state) { state.last_token_refresh_time = new Date().getTime() Cookies.set('last_token_refresh_time', state.last_token_refresh_time) }, }})

上面的代码展示了怎么样通过vuex来管理和操作token,但是配置好了之后应该怎么调用呢? 其实在Login.vue中已经使用过了,我在这里再解释一下。

首先要引入,可以看Login.vue里面import部分的最后一行,也就是 import store from '../../store/index.js';通过store.commit(函数名,参数)的方法调用,比如 store.commit('setAccessToken', res.data.access)

好了,到这里基本就大功告成了,再项目的根目录下把项目运行起来,然后在浏览器中输入 http://localhost:5173/#/login 就会出现登录页面,账号和密码分别是admin和Pass1234,输入之后点击登录应该就能跳转到首页了。

记住在运行项目之前先安装依赖,执行cnpm install。

虽然到这里登录功能基本完成了,还是还缺一点。 大家有没有发现,到目前为止,虽然登录功能可以工作了,但是访问者依然可以在没有登录的情况下就访问所有的页面,也就是没有起到限制的作用,这个叫做路由守卫或者导航守卫,下面介绍。

路由守卫

路由守卫的内容上面介绍过了,实现起来其实比较简单,在main.js里面配置,main.js修改后内容如下,

import { createApp } from 'vue'import App from './App.vue'import ElementPlus from 'element-plus'import 'element-plus/dist/index.css'import router from './router/index.js'import api from './api/api.js'import * as ElementPlusIconsVue from '@element-plus/icons-vue'import './assets/main.css'import store from './store/index.js'const app = createApp(App)for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component)}router.beforeEach((to, from, next) => { store.commit('getAccessToken') const token = store.state.access_token if (!token && to.name !== 'login') { next({ name: 'login' }) } else if (token && to.name === 'login') { next({ name: 'home' }) } else ( next() )})app.use(router)app.use(ElementPlus)app.mount('#app')app.config.globalProperties.$api = api

修改了两部分,

引入storeimport store from './store/index.js'配置路由守卫router.beforeEach((to, from, next) => { store.commit('getAccessToken') const token = store.state.access_token if (!token && to.name !== 'login') { next({ name: 'login' }) } else if (token && to.name === 'login') { next({ name: 'home' }) } else ( next() )})

这一段代码的作用就是判断access_token是否存在,如果存在就放行,如果不存在就跳转到登录页面。 理解这一段代码的时候要结合Login.vue里面的login这个函数,这个函数在登录校验通过之后运行了 store.commit('setAccessToken', res.data.access) 和 store.commit('setRefreshToken', res.data.refresh) ,这两行代码的作用就是更新(设置)access token 和refresh token,换句话说,登录成功之后,access token一定存在,如果access token不存在就可以认为没有登录或者没有登录成功,所以在路由守卫中可以利用access token来作为判断条件。

到这里,等个登录模块就完全做好了。

其实登录功能本身很简单,但是这个笔记里面讲到了vue3中api的管理,axios的封装,vuex的使用,所以会有点难。

思考题

最后留三个思考题:

现在的登录页面在输入账号密码之后一定要鼠标点击登录按钮才能登录,在输入框内按回车键是不行的,可以考虑一下怎么实现加上登录模块之后,访问者一定要登录之后才能访问,但是也有的系统是允许匿名访问的,只有在做一些特定的操作的时候才需要登录,这个要怎么实现 ?当前系统,所有访问者在登录之后能够访问的页面是一样的,但是项目中经常会需要根据访问者的权限不同开放不同页面,这个要怎么实现 ?
本文链接地址:https://www.jiuchutong.com/zhishi/300539.html 转载请保留说明!

上一篇:MMEngine理解

下一篇:PDFBox 优化内存方案(pdf优化器在哪里)

  • 控股股东无偿捐赠
  • 应付债券利息调整是什么意思
  • 房地产简易征收可以开专用发票吗
  • 企业计提的资产包括哪些
  • 银行存款转存利息一样吗
  • 出口退税免税申报怎么报
  • 境外机构在境内发行的人民币债券
  • 怎么看医疗报销单
  • 汇算清缴职工福利支出
  • 上级拨付的固定资产增加类型是什么
  • 影视发行收入该如何做税收处理?
  • 联营商品如何做账
  • 核销的方式
  • 营改增工程计价规则
  • 有关增值税期末留抵税额的会计分录
  • 工程款发票备注栏项目名称
  • 新金融工具准则投资收益
  • 对公账户的利息收入如何入账
  • 付款凭证和记账凭证一样吗
  • 1697507882
  • mac怎么设置屏幕保护壁纸
  • 总承包简易计税
  • 期末坏账准备的计算
  • 年度所得税报表在哪里查到
  • 客户尾款不付会计分录
  • 留抵增值税可以冲营业外支出吗
  • algarin.exe什么意思
  • dcom进程
  • 员工补偿金分录
  • 营业外收入的会计要素
  • yii2框架运行原理
  • php获取文件名后缀
  • 小企业会计准则2023电子版
  • 收取的延期付款利息会计调账处理
  • vue ts
  • 设计部工资计入什么费用
  • lvs安装配置
  • 会计打印发票请求怎么写
  • websocket()
  • es6promise的理解
  • php的序列化操作生成的哪种格式
  • 税盘显示已反写
  • 公司出售房子怎么交税
  • mysql入门很简单
  • 应收账款收不回来做坏账处理分录
  • 固定资产的
  • 税控盘怎么看是否清盘
  • 小规模公司注销时账务要如何处理
  • 中小型企业营业额和从业人数
  • 纳税调整调减有哪些
  • 对增值税发票开具方面是有何要求?
  • 用负数表示的例子
  • 建筑施工企业适用什么会计制度
  • 商品亏本出售分录
  • 把上级机关来文转给下级机关的通知
  • 营业税差额征税范围
  • 疫情期间公司购买物品
  • 借款收据怎样才有法律效力
  • 误餐补助标准国家规定
  • 水表怎么借水
  • 营改增后,小规模纳税人广联达
  • sqlserver数据库中表的类型有哪些
  • mysql数据库-数据库和表的基本操作
  • 系统存储过程以什么开头
  • 主板如何清除cmos
  • centos如何挂载fc存储
  • ahqtb.exe是啥进程 ahqtb进程信息查询
  • 电脑任务栏中没有网络图标
  • mount挂载文件系统
  • linux系统ll
  • opengl extension
  • 深入python3
  • linux常用脚本代码
  • 首次安装操作系统称为什么盘
  • js设置密码长度
  • jquery?
  • javascript开发基础
  • 出口退税期限最长几个月以上
  • 税务机关代收工会经费手续费
  • 国税局征收的税种有哪些?
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设