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

Vuex身份认证

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

  • 应当在用户登录成功之后给用户生成一个标记(令牌),将这个令牌保存起来
  • 在用户访问任意需要登录的页面(组件)的时候都要去验证令牌
  • 从而识别到用户是否登录或者是否有权限去访问对应的功能
    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.dtcms.com/a/267099.html

相关文章:

  • 《C++初阶之类和对象》【经典案例:日期类】
  • Java创建型模式---单例模式
  • WSL命令
  • C#每日学习日记
  • 3dmax烘焙插件3dmax法线贴图烘焙教程glb和gltf元宇宙灯光效果图烘焙烘焙光影贴图支持VR渲染器
  • AWS WebRTC:通过shell分析viewer端日志文件
  • 深入解析享元模式:通过共享技术高效支持大量细粒度对象
  • 【力扣 简单 C】70. 爬楼梯
  • 【鸿蒙】鸿蒙操作系统发展综述
  • 递归与循环
  • 深入理解Reactor调试模式:Hooks.onOperatorDebug() vs ReactorDebugAgent.init()
  • 软件工程经济与伦理
  • 流水线(Jenkins)打包拉取依赖的时候提示无法拉取,需要登录私仓的解决办法
  • HTML知识复习2
  • HuggingFists: 无代码处理复杂PDF
  • 一个简单的网页设计
  • Vue Router 中,params参数的名称必须与路由配置中的动态路径参数名完全一致
  • Go语言基础之接口
  • CppCon 2018 学习:Sane and Safe C++ Class Types
  • FLAN-T5:规模化指令微调的语言模型
  • NumPy 函数库在数学建模中的基本使用方法
  • 电脑休眠控制工具,灵活设置防休眠
  • 通过 Windows 共享文件夹 + 手机访问(SMB协议)如何实现
  • Python(28)Python循环语句指南:从语法糖到CPython字节码的底层探秘
  • Everything 1.5.0.1393a高效实用的系统文件搜索工具(2025年7月4日更新)
  • 构建未来交互体验:AG-UI 如何赋能智能体与前端通信?
  • [论文阅读] 软件工程 | 可持续性标志在问答平台中的应用
  • AI语音训练——GPT-SoVITS(GSV)
  • Vue 笔记:动态绑定内联样式 :style 的关键语法注意事项
  • Spring Boot 框架创建一个简单的后端接口,并介绍如何使用 Apifox 连接该接口