虽说上一节我们实现了登录功能,但是实际上还是可以通过浏览器的地址来跳过登录访问到后台,这种可有可无的登录功能使得系统没有安全性,而且没有意义
为了让登录这个功能有意义,我们应该:

  • 应当在用户登录成功之后给用户生成一个标记(令牌),将这个令牌保存起来
  • 在用户访问任意需要登录的页面(组件)的时候都要去验证令牌
  • 从而识别到用户是否登录或者是否有权限去访问对应的功能
    1.成功时,访问组件
    2.失败时,进行提示
    如何让login组件中的数据被任意其他组件访问呢?这个时候可以使用vue官方的状态管理工具Vuex

Vuex

Vuex是一个专门为Vue.js应用程序开发的状态管理模式
文档:

https://vuex.vuejs.org/zh

  • Vuex是专门为Vue.js设计的状态管理库
  • 采用集中式的方式存储需要共享的数据
  • 本质上就是一个JavaScript库
  • 用来解决复杂组件通信,数据共享的问题
    简单来说就是Vuex用来统一存储需要在多个组件间共享的状态(数据),状态可以被任意组件操作,使得组件通信变得易如反掌

那么归根到底,我们是否需要Vuex,要根据什么来判断呢?

  • 多个视频依赖于同一个状态
  • 来自不同视图的行为需要变更同一状态
    安装Vuex
    通过npm安装:
npm install vuex -S

使用Vue CLI创建项目的时候,可以在项目选项中选择Vuex,这个时候就不需要再单独安装了,这边我们已经在创建项目的时候安装过了Vuex,所以不再多做操作

使用

创建Vuex实例store,store通常称之为"容器"
文件,store/index.js



main.js导入,根Vue实例中引入Vuex作为插件

通过Vue.use()引入Vuex中,Vuex的功能被注入到根实例下的所有子组件中,可以通过$store访问到内部功能
我们的项目通过VueCLI创建时已经选择了Vuex,所以创建和引入都已经被Vue CLI自动完成了

State

容器中的state用于存储需要在组件之间共享的数据

  • 容器中的数据可以被任意组件访问
  • 容器中的数据为响应式数据
    state存储count

    Vue官方调试工具也可以看到数据

    在组件中,通过vm.$store.state.状态名访问
// login/index.vue
methods: {async onSubmit () {console.log(this.$store.state.user)...}
}

Mutation

来源:官方文档

简单来说,要修改Vuex的state,必须提前定义Mutation函数,需要的时候再进行提交,Mutation接收state对象作为第一个参数,用于操作state内部的数据

// store/index.js
export default new Vuex.Store({state: {user: 100},mutations: {setUser (state) {state.user++}},actions: {},modules: {}
})

在组件中通过vm.$store.commit('Mutation名称')提交Mutation,执行操作

// login/index.vue
methods: {async onSubmit () {console.log(this.$store.state.user)this.$store.commit('setUser')console.log(this.$store.state.user)...}
}

Mutation还接受提交载荷(payload)作为第二个参数,指的是commit()传入的额外数据,常常需要根据上下文数据修改state使用

// store/index.js
mutations: {setUser (state, payload) {state.user = payload}
},
// login/index.vue
methods: {async onSubmit () {this.$store.commit('setUser', '示例内容')...}
}

但是实际上在大多数情况下,载荷应该是一个对象才对,这样就可以包含多个字段并且记录的mutation会更易读:

mutations: {increment (state, payload) {state.count += payload.amount}
}
store.commit('increment', {amount: 10
})
文档中的另一种对象风格的提交方式,可以记录一下

Mutation的设置方式使得Vuex的状态修改有迹可循,易于维护,如果state可以通过赋值修改,一旦出错了就找不到错误点了
除此之外,Vue Devtools还提供了Vuex更高级的调试方式Time Travel

可以回溯到特定的操作点上进行调试

Mutation必须为同步函数,由于DevTools提供了Mutation日志功能,为了确保功能正常,内部不能存在异步任务,否则DevTools将无法得知Mutation的准确调用顺序,如果需要进行异步操作,那么则需要Vuex的Action

Action

Action类似于Mutation,不同的地方在于:

  • Action提交的是Mutation,而不是直接变更状态
  • Action可以包含任意的异步操作
    Action 函数接受一个与store实例具有相同方法和属性的context对象,因为可以调用context.commit提交一个Mutation
// store/index.js
actions: {addAction (context) {setTimeout(function () {context.commit('setUser')}, 1000)}
},

在实机操作中,我们经常用到ES2015的参数结构来简化代码(就比如我们在解构后端传来的数据一样,直接{ data }),这种情况尤其是出现在我们需要多次调用commit的时候

  actions: {// jia (context) {//   context.commit('jia')// }jia ({ commit }) {commit('jia')}},

Action 通过 vm.$store.dispatch方法触发,参数1为action名称,参数2为payload

// login/index.vue
methods: {async onSubmit () {this.$store.dispatch('addAction')...}
}

Vuex 核心概念还有Getter和Module,可以通过文档来进行学习

身份认证

登录状态存储

获取能够在任意组件中访问用户的登录信息,我们将状态存储在Vuex中

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {user: null},mutations: {setUser (state, payload) {state.user = payload}},actions: {},modules: {}
})

声明Mutation拿来用于修改user数据,具体内容采用payload载荷方式传入,我们可以通过devtools调试工具查看
观察到通过接口传来的数据,我们应该拿来存入的是data.content,内部为用户的相关信息。

// login/index.js
methods: {async onSubmit () {try {...// 当登录成功时,记录登录状态,存储到 Vuex 中this.$store.commit('setUser', data.content)this.$router.push({name: 'home'})this.$message.success('登录成功')} catch (err) {console.log('验证失败', err)}}
}

那么又因为传来的数据是JSON格式,为了以后方便我们的使用,我们应该在Mutation的setUser中转换为对象保存,可以通过DevTools调试工具查看到,然后就是通过本地存储的方式对user进行数据持久化,避免页面刷新后丢失,存储成功之后呢,就可以将user的初始值更改为本地存储获取user的数据

  state: {// 用于登录成功后保存用户信息的(初始值尝试读取本地存储user: JSON.parse(window.localStorage.getItem('user') || null)},mutations: {// 存储用户数据setUser (state, payload) {// 将payload转换为对象后进行存储state.user = JSON.parse(payload)// 将payload的数据添加到本地存储中// 本地存储只能存储字符串window.localStorage.setItem('user', payload)}},

校验页面访问权限

路由跳转时,需要校验登录状态,根据结果进行后续处理
这里使用Vue Router的导航守卫beforeEach,在任务导航被触发的时候进行登录状态监测,当前后台页面都需要登录状态,但是有些页面不需要登录状态的话,这个该如何处理呢?
使用:Vue Router的路由元信息功能来设置
下面给需要设置登录状态的路由添加路由元信息(比如我们把home页面的子路由的部分设置为需要登录)

  • meta用于保存与路由相关的自定义数据
  • requiresAuth表示是否需要认证,true为需要



    用户登录状态保存在store(Vuex)中,需要引入文件来读取数据检测,在导航守卫中检测to的路由是否需要登录

// 全局前置守卫
router.beforeEach((to, from, next) => {// 验证 to 路由记录是否需要进行身份认证if (to.matched.some(record => record.meta.requiresAuth)) {// 验证Vuex 的 store 中的用户信息是否存储if (!store.state.user) {// 未登录,跳转到登录页面return next({ name: 'login' })}// 已经登录,允许通过next()} else {// 无需登录,允许通过next() // 确保一定要调用 next()}
})

登录后跳转到上次访问页面

上一次我如果访问了用户管理/user,过了一段时间状态过期,直接访问路由/user,跳转到login,登陆之后又跳转了首页。如果我希望登录后直接跳转到user而不是首页,我们就应该在每次跳转到/login时记录当前to目标的路由信息,这个时候就可以通过跳转路由的query属性进行设置

//router/index.jsif (!store.state.user) {// 未登录,跳转到登录页面next({name: 'login',query: {// 将本次路由的fullpath传递给login页面// path仅包含路径,fullpath为完整url(包含了查询字符串参数等信息)redirect: to.fullPath}})}

那么在登录页中,登陆成功的跳转时,应该检测是否存在登录前的页面信息,有就跳转,没有就默认跳转首页


变更了一下push顺序,防止出现路由重定向提前

除了登录过期以外,例如将页面存储书签,或者点击其他人发送的链接访问,都可以在登陆之后自动跳转到对应的路由,提高了我们的体验


删除掉本地用户信息后使用对应路由打开网页就可以在登录后定向到指定的路由了

用户信息与接口鉴权

用户基本信息接口:接口
首先使用postman进行接口测试
在集合中添加一个新的请求,设置基本信息


发送请求,发现传回来的是错误信息
HTTP状态码是401,状态文本为'Unauthorized'未授权

这个时候就说明接口需要授权才能访问,查询了接口的说明文档可以得知,需要一个名为“Authotization”的请求参数(位于请求头),用于验证 授权信息,这种验证接口的授权的处理方式我们称之为接口鉴权

得出两条结论:

  • 后端提供的接口是没法随便访问的
  • 使用接口前需要进行接口的鉴权处理
    那么我们该怎么获得权限去获取后端返回的数据呢?

Token

一种常用的接口鉴权方式
Token是在用户登陆成功之后,由服务端生成的一段保存了用户身份信息,加密的字符串
生成之后,通过响应方式将token信息响应到服务端,通过之前的登录接口响应成功时可以看到

将其复制下来,保存到用户基本信息接口的请求头上

请求头Authorization

就能得到信息啦,接口鉴权成功

Postman统一设置token

后续我们要用到的这个集合的接口会更多,每次都写Token的话就要被烦到,所以我们可以使用Postman提供的统一设置方式





保存了之后,回到用户信息接口会发现我们单独设置的authorization提示了已经被统一设置的信息,我们就可以将自己设置的给删除掉,再次发送请求也是没有问题的

实现用户信息展示

测试处理完毕之后,我们需要在代码中进行Token处理和功能实现
首先要封装用于用户信息请求的方法,在header最后那个设置Token,引入store用于读取token



接着在app-header组件中引入功能,并且在created钩子函数中请求数据,并将其数据绑定到视图中

<script>
// 引入用户信息接口功能
import { getUserInfo } from '@/services/user'export default {name: 'AppHeader',created () {// 加载用户信息// 钩子函数不建议书写代码逻辑,最好直接使用封装好的函数this.loadUserInfo()},data () {return {// 用户信息userInfo: {}}},methods: {async loadUserInfo () {const { data } = await getUserInfo()// console.log(data)this.userInfo = data.content}}
}
</script>
绑定数据

通过请求拦截器设置Token

通过Axios的请求拦截器进行统一设置Token
很多请求都是需要在header设置Token信息的,可以通过Axios拦截器进行统一处理
Axios拦截器与导航守卫相似,可以在任意请求和响应前进行拦截处理,功能分为:

  • 请求拦截器
  • 响应拦截器
    通过请求拦截器参数config.headers可以访问请求头,将store中的Token统一设置就可以了
// 设置请求拦截器
request.interceptors.request.use(function (config) {
// 判断config.url的前缀是什么,然后进行请求baseURL的设置config.baseURL = getBaseURL(config.url)// 统一的token信息设置// 为了严谨,可以读取store中的user后进行Token检测const { user } = store.stateif (user && user.access_token) {// 设置tokenconfig.headers.Authorization = user.access_token}return config
})

这个拦截器设置之后呢,services/user.js中的getUserInfo内部的Token设置就可以删除了,同时也可以去掉store的引入

// services/user.js
...
// import store from '@/store'
...
// 用户基本信息请求
export const getUserInfo = () => {return request({method: 'GET',url: '/front/user/getInfo'// 在 header 中设置 Token 信息(统一设置后去除,记得去除上一行的分号)/* headers: {Authorization: store.state.user.access_token} */})
}

用户退出

首先我们要给退出按钮设置点击事件,发现其实是触发不了的,那是因为我们使用的是Element组件,这里的退出按钮是组件,而组件设置的都是自定义事件

// app-header.vue
<el-dropdown-itemdivided@click="handleLogout"
>退出</el-dropdown-item>...methods: {...// 退出按钮功能handleLogout () {console.log('点击退出')}
}

我们可以使用事件修饰符.native来监听组件根元素的原生事件

// app-header.vue
<el-dropdown-itemdivided@click.native="handleLogout"
>退出</el-dropdown-item>

点击退出后,清除store内部的用户信息,同时跳转回到登录页面

  • 通过mutation中的setUser清空user,由于setUser也设置了本地存储,这个时候也会自动清空
// 退出功能handleLogout () {// 清除store的用户信息this.$store.commit('setUser', null)// 跳转登录页this.$router.push('/login')}

可以通过Element的MessageBox弹框组件进行退出确认提示,增强体验感

  • 确认提示使用&confirm(),确定触发then(),取消触发catch()
  • 按钮内容默认为确定和取消,如不更改可以删除
    在点击退出按钮时,通过this,$confirm()进行确认消息设置
  • 将前面设置的退出功能移步到位确认退出的代码区域
// 退出功能handleLogout () {this.$confirm('确认退出吗?', '退出提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {// 清除store的用户信息this.$store.commit('setUser', null)// 跳转登录页this.$router.push('/login')this.$message({type: 'success',message: '退出成功!'})}).catch(() => {this.$message({type: 'info',message: '取消退出'})})}

以上,登录功能到认证到退出一个闭环功能完成了,完善程度很高



喜欢的朋友记得点赞、收藏、关注哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87646.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87646.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87646.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot中使用线程池

1.什么场景下使用线程池&#xff1f; 在异步的场景下&#xff0c;可以使用线程池 不需要同步等待&#xff0c; 不需要管上一个方法是否执行完毕&#xff0c;你当前的方法就可以立即执行 我们来模拟一下&#xff0c;在一个方法里面执行3个子任务&#xff0c;不需要相互等待 …

Flask+LayUI开发手记(十):构建统一的选项集合服务

作为前端最主要的组件&#xff0c;无论是layui-table表格还是layui-form表单&#xff0c;其中都涉及到选项列的处理。如果是普通编程&#xff0c;一个任务对应一个程序&#xff0c;自然可以就事论事地单对单处理&#xff0c;前后端都配制好选项&#xff0c;手工保证两者的一致性…

redis的数据初始化或增量更新的方法

做系统开发的时候&#xff0c;经常需要切换环境&#xff0c;做一些数据的初始化的工作&#xff0c;而redis的初始化&#xff0c;假如通过命令来执行&#xff0c;又太复杂&#xff0c;因为redis有很多种数据类型&#xff0c;全部通过敲击命令来初始化的话&#xff0c;打的命令实…

【PaddleOCR】OCR表格识别数据集介绍,包含PubTabNet、好未来表格识别、WTW中文场景表格等数据,持续更新中......

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

sparkjar任务运行

mainclass&#xff1a; test.sparkjar.SparkJarTest

Web攻防-文件下载文件读取文件删除目录遍历路径穿越

知识点&#xff1a; 1、WEB攻防-文件下载&读取&删除-功能点&URL 2、WEB攻防-目录遍历&穿越-功能点&URL 黑盒分析&#xff1a; 1、功能点 文件上传&#xff0c;文件下载&#xff0c;文件删除&#xff0c;文件管理器等地方 2、URL特征 文件名&#xff1a; d…

使用LIMIT + OFFSET 分页时,数据重复的风险

在使用 LIMIT OFFSET 分页时&#xff0c;数据重复的风险不仅与排序字段的唯一性有关&#xff0c;还与数据变动&#xff08;插入、删除、更新&#xff09;密切相关。以下是详细分析&#xff1a; 一、数据变动如何导致分页异常 1. 插入新数据 场景&#xff1a;用户在浏览第 1 页…

Excel 数据透视表不够用时,如何处理来自多个数据源的数据?

当数据透视表感到“吃力”时&#xff0c;我们该怎么办&#xff1a; 数据量巨大&#xff1a;Excel工作表有104万行的限制&#xff0c;当有几十万行数据时&#xff0c;透视表和公式就会变得非常卡顿。数据来源多样&#xff1a;数据分散在多个Excel文件、CSV文件、数据库甚至网页…

cf(1034)Div3(补题A B C D E F)

哈&#xff0c;这个比赛在开了不久之后&#xff0c;不知道为啥卡了差不多20来分钟&#xff0c;后面卡着卡着就想睡觉了。实在是太困了.... 题目意思&#xff1a; Alice做一次操作&#xff0c;删除任意数字a,而Bob做一次操作删除b使得ab对4取余是3。 获胜条件&#xff0c;有人…

浏览器与服务器的交互

浏览器地址栏输入URL&#xff08;网址​​&#xff09; ​​​​(1) 服务器进行URL解析​​&#xff1a;验证URL格式&#xff0c;提取协议、域名等 ​​​​(2) 服务器进行DNS查询​​&#xff1a;将域名转换为IP地址&#xff08;可能涉及缓存或DNS预取&#xff09; ​​​​…

Spring Boot中POST请求参数校验的实战指南

在现代的Web开发中&#xff0c;数据校验是确保应用程序稳定性和安全性的关键环节。Spring Boot提供了强大而灵活的校验机制&#xff0c;能够帮助开发者轻松地对POST请求参数进行校验。本文将详细介绍如何在Spring Boot中实现POST请求参数的校验&#xff0c;并通过具体的代码示例…

Spring Boot + MyBatis/MyBatis Plus:XML中循环处理List参数的终极指南

重要提醒&#xff1a;使用Param注解时&#xff0c;务必导入正确的包&#xff01; import org.apache.ibatis.annotations.Param; 很多开发者容易错误导入Spring的Param&#xff0c;导致参数绑定失败&#xff01; 一、为什么需要传递List参数&#xff1f; 最常见的场景是动态构…

Design Compiler:自适应重定时(Adaptive Retiming)

相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 简介 重定时是DC Ultra引入的一种时序优化技术&#xff0c;可以将时序单元&#xff08;触发器和锁存器&#xff09;穿越组合逻辑前后移动&#xff0c;以优化设…

解决kali Linux在VMware中的全局缩放问题

在每次启动kali时&#xff0c;因为屏幕分辨率过高&#xff0c;系统整体特别小&#xff0c;该怎么操作调整合适呢 在搜索中搜索kali HiDPI Mode 选择yes 然后就会自动调整合适了

Python关键字梳理

在 Python 中&#xff0c;关键字&#xff08;Keywords&#xff09;是具有特殊含义的保留字&#xff0c;它们用于定义语法和结构。async 是 Python 3.5 引入的关键字&#xff0c;用于支持异步编程&#xff08;Asynchronous Programming&#xff09;。下面我将详细讲解 async 及其…

结构体实战:用Rust编写矩形面积计算器

文章目录结构体实战&#xff1a;用Rust编写矩形面积计算器&#x1f4d0; 问题描述1️⃣ 基础版&#xff1a;独立变量&#xff08;混乱版&#xff09;2️⃣ 进阶版&#xff1a;使用元组3️⃣ 终极版&#xff1a;使用结构体&#xff08;优雅版&#xff09;&#x1f3af; 运行结果…

基于开源链动2+1模式AI智能名片S2B2C商城小程序的场景零售创新研究

摘要&#xff1a;本文聚焦场景消费逻辑&#xff0c;探讨开源链动21模式AI智能名片S2B2C商城小程序在场景零售中的应用。通过分析场景消费中消费者体验的关键作用&#xff0c;结合该技术组合的特性&#xff0c;阐述其如何优化场景内容、增强场景美感&#xff0c;为消费者创造超乎…

新发布:26考研院校和专业大纲

复习方向错了&#xff0c;努力可能白费 近日&#xff0c;多所高校陆续发布2026年硕士研究生招生考试自命题科目大纲&#xff0c;为备考的学子们指明了复习方向。今年的考纲有哪些重要变化&#xff1f;又该如何应对&#xff1f;本文为你全面梳理&#xff01; 院校和专业发布详情…

matlab/Simulink-全套50个汽车性能建模与仿真源码模型9

50个simulink模型&#xff08;所有模型罗列如下&#xff0c;没罗列就是没有&#xff0c;包含子模块总共50个。&#xff09; 基于汽车驱动力-行驶阻力平衡图的汽车动力性仿真模型 基于汽车动力特性图的汽车动力性仿真模型 基于汽车功率平衡图的汽车动力性仿真模型 电动汽车动力…

为什么星敏感器(Star Tracker)需要时间同步?—— 从原理到应用的全解析

为什么星敏感器&#xff08;Star Tracker&#xff09;需要时间同步&#xff1f;—— 从原理到应用的全解析 引言 在卫星姿态控制系统中&#xff0c;星敏感器&#xff08;Star Tracker, 简称“星敏”&#xff09; 是最精确的姿态测量设备之一&#xff0c;其精度可达角秒级&…