这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
身份认证简介
- 🤩避免"有门无墙",为了让登录功能变得有意义
- 应当在用户登录成功后给用户生成一个标记(令牌),并将这个令牌保存起来
- 在用户访问任意需要登陆的页面(组件)时都去验证令牌
- 从而识别用户是否登录或是否有权访问对应功能
- 成功,访问组件
- 失败,进行提示
Vuex
- 使用
vue
官方的状态管理工具vuex
,实现让login
组件中的数据被任意其他组件访问 - 🤩
vuex
用来统一存储需要在多个组件间共享的状态(数据),状态可以被任意组件操作,是组件通信变得易如反掌
项目中使用vuex
- 安装
npm i vuex -S
- 使用:创建
vuex
实例store
(容器)
// store/index.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
// 创建vuex容器实例,用来存储需要在组件中共享的状态
const store = new Vuex.store({
state: {
count: 0
}
})
export default store
- 在根
vue
实例中引入vuex
作为插件
new Vue ({
render: h => h(App),
store
}).$mount("#app")
- 通过
vue.use()
引入Vuex
后,Vuex
功能被注入到根实例下的所有子组件中,可通过$store
访问内部功能
state
- 容器中
state
用于存储需要在组件间共享的数据 - 特点
- 容器中的数据可以被任意组件访问
- 容器中的数据为响应式数据
export default new Vuex.store({ state: { user: 'zs' }, // 唯一提交state的方法 mutations: { }, // 异步操作 actions: { }, // 模块 modules: { } })
- 在组件中通过
this.$store.state.状态名
访问
async onSubmit () {
console.log(this.$store.state.user)
}
Mutation
- 要修改
Vuex
中的state
,必须提前定义Mutation
函数,需要提交时再进行提交 - 🤩
Mutation
接收state
对象为第一个参数,用于操作state
内的数据 - 代码演示
export default new Vuex.store({
state: {
age: 18
},
mutations: {
// 第一步:定义mutation函数
setAge (state) {
state.age++
}
}
})
- 需要提交(修改
state
的时候执行)
async onSubmit () {
// 打印输出age
console.log(this.$store.state.age)
// 第二步:提交mutation,执行操作
this.$store.commit('setAge')
console.log(this.$store.state.age)
}
Mutation
还接收提交载荷payload作为第二个参数,常在需要根据上下文数据修改state
时使用
// store/index.js
mutations: {
setAge (state,payload) {
state.age = payload
}
}
// 组件中
async onSubmit() {
this.$store.commit('setAge',23)
}
注意点
Mutation
的设置方式使Vuex
的状态修改有迹可循,易于维护。Vue DevTools
提供了用于Vuex
更高级的调试方式Time Travel
- 🤩
Mutation
必须是同步函数- 因为
DevTools
提供了Mutation
日志功能,为了确保功能正常,内部不能存在异步任务,否则DevTools
将无法得知Mutation
的准确调用顺序。
- 因为
Action
Action
类似于mutation
不同在于Action
提交的是Mutation
,而不是直接变更状态Action
可以包含任意异步操作
- 🤩
Action
函数接受一个与store
实例具有相同方法和属性的context
对象,因此你可以调用context.commit
提交一个Mutation
// store/index.js
mutations: {
setAge (state,payload) {
// 修改状态
state.age = payload
}
},
actions: {
// context与store实力具有相同的方法与属性
addAction (context,payload) {
setTimeout (function () {
// 提交mutation
context.commit('setAge',payload.age)
}, payload.time)
}
}
- 🤩
Action
通过this.$store.dispatch
方法触发
// login/index.vue
async onSubmit() {
this.$store.dispatch('addAction',{ age: 10, time: 1000})
}
数据持久化
- 🤩将状态通过本地存储方式
localStorage
对user
进行数据持久化,避免页面刷新后状态丢失
state: {
age: JSON.parse(window.localStorage.getItem('user') || null)
},
mutations: {
setAge (state,payload) {
// 转换为 对象 进行保存
state.age = JSON.parse(payload)
// 通过本地存储实现数据持久化
window.localStorage.setItem('user',payload)
}
}
校验页面访问权限
-
🤩路由跳转时,需要验证登陆状态,使用
Vue Router
导航守卫beforeEach
,在任务被触发时进行登录状态检测 -
🤩如果需求中只有部分页面需要登陆状态的话,可以通过
Vue Router
中的路由元信息功能来设置meta
:保存与路由相关的自定义数据requiresAuth
: 是否需要认证,true
需要认证
// router/index.js // 路由规则 const routes = [ { path: '/course', name: 'course', component: () => import(/* webpackChunkName: 'course' */'@/views/course/index.vue'), // 对需要身份验证的路由进行身份验证 meta: { requiresAuth: true } } ]
-
在导航守卫中检测
to
的路由是否需要登录
// 设置VueRouter的前置守卫,进行路由跳转权限验证
router.beforeEach((to, from, next) => {
// 官方示例
if (to.matched.some(record => record.meta.requiresAuth)) {
// 如果能从vuex中的store容器中取到身份信息,那么就身份认证成功
if (!store.state.user) {
console.log('未登录')
next({
// 需要跳转的路由名称
name: 'login'
})
} else {
// 已经登陆
next()
}
} else {
// 不要身份验证
next() // 确保一定要调用 next()
}
})
路由元信息优化操作
- 如果某个父路由下的所有子路由均需要登录,可以直接给父路由设置
meta
处理(统一处理) - 因为子路由请求会经过父路由,直接给父路由设置登陆检测更加简单,适合所有子路由均需要登录的情况
登陆后跳转到上次访问页面
- 应当在每次跳转到
/login
时记录当前to
目标路由信息,通过跳转路由query
属性进行设置
if (!store.state.user) {
next({
// 需要跳转的路由名称
name: 'login',
// 跳转路由需要携带的参数信息 redirect为自定义名称
query: { redirect: to.fullPath }
})
}