传统方式中,许多人使用本地存储,来管理通过客户端验证生成的tokens。一个大问题是如何有更好的方式,来管理验证tokens,从而允许我们来存储更大的用户信息。
这就是Vuex的作用。 vuex为Vue.js应用管理状态.。对于应用中所有的组件来说,它被当做中央存储,并用规则确保状态只能以可预见的方式改变。
对于经常检查本地存储来说,听起来是个更好的选择?让我们一起来探索下吧。
对于这个项目,我们想创建一个使用vuex和vue-router的vue应用。我们会使用vue cli 3.0 来创建一个vue项目,并从选项中选择路由和vuex。
执行下面的命令开始创建:
$ vue create vue-auth
按照对话框的提示,添加必要的信息,并选择我们需要的选项,完成安装。
下一步, 安装axios:
$ npm install axios --save
我们在许多组件中都需要用到axios。让我们在全局整体来配置它,这样当我们需要它的时候,不用每次都去引入。
打开 ./src/main.js 文件,并且添加下面:
[...]
import store from './store'
import Axios from 'axios'
Vue.prototype.$http = Axios;
const token = localStorage.getItem('token')
if (token) {
Vue.prototype.$http.defaults.headers.common['Authorization'] = token
}
[...]
现在,当我们想在组件内使用axios时, 我们可以用this.$http ,这样相当于直接是axios。我们也可以在axios头部给自己的token, 设置身份验证,这样如果token是必需的,我们的请求将处于控制中。在这种方式下,当我们想要发送请求时,任何时候都不用设置token。
相关课程: Vue创建一个网上商店
完成之后,让我们使用服务器来处理身份验证。
我已经写过关于这个,在我解释如何用vue-router来解决身份验证时。仔细看看Setup Node.js Server 这个章节。
创建Login.vue 在 ./src/components 目录下。 之后, 给登录页面添加模板:
<template>
<div>
<form class="login" @submit.prevent="login">
<h1>Sign in</h1>
<label>Email</label>
<input required v-model="email" type="email" placeholder="Name"/>
<label>Password</label>
<input required v-model="password" type="password" placeholder="Password"/>
<hr/>
<button type="submit">Login</button>
</form>
</div>
</template>
当你做完之后, 添加data属性,将其绑定到html表单中:
[...]
<script>
export default {
data(){
return {
email : "",
password : ""
}
},
}
</script>
现在, 让我们给登录添加方法:
[...]
<script>
export default {
[...]
methods: {
login: function () {
let email = this.email
let password = this.password
this.$store.dispatch('login', { email, password })
.then(() => this.$router.push('/'))
.catch(err => console.log(err))
}
}
}
</script>
我们正在使用vuex的action — login 来解决身份验证。我们可以在将actions细化到回调里面,这样就可以在自己的组件里面做一些很酷的事情了。
跟login组件类似,那我们给注册用户弄一个了。在组件目录里面创建Register.vue ,并将下面的添加进去:
<template>
<div>
<h4>Register</h4>
<form @submit.prevent="register">
<label for="name">Name</label>
<div>
<input id="name" type="text" v-model="name" required autofocus>
</div>
<label for="email" >E-Mail Address</label>
<div>
<input id="email" type="email" v-model="email" required>
</div>
<label for="password">Password</label>
<div>
<input id="password" type="password" v-model="password" required>
</div>
<label for="password-confirm">Confirm Password</label>
<div>
<input id="password-confirm" type="password" v-model="password_confirmation" required>
</div>
<div>
<button type="submit">Register</button>
</div>
</form>
</div>
</template>
让我们定义一下这些将绑定到表单里面的data属性:
[...]
<script>
export default {
data(){
return {
name : "",
email : "",
password : "",
password_confirmation : "",
is_admin : null
}
},
}
</script>
现在,让我们添加方法进去:
[...]
<script>
export default {
[...]
methods: {
register: function () {
let data = {
name: this.name,
email: this.email,
password: this.password,
is_admin: this.is_admin
}
this.$store.dispatch('register', data)
.then(() => this.$router.push('/'))
.catch(err => console.log(err))
}
}
}
</script>
让我们创建一个普通的组件,它在用户通过验证后会显示。文件命名为Secure.vue,并添加下面的进去:
<template>
<div>
<h1>This page is protected by auth</h1>
</div>
</template>
打开./src/App.vue 文件,并添加下面的进去:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link><span v-if="isLoggedIn"> | <a @click="logout">Logout</a></span>
</div>
<router-view/>
</div>
</template>
如果用户登录进去后,你能看到关联的Logout了 吗?很好。
现在,让我们给logout添加逻辑。
<script>
export default {
computed : {
isLoggedIn : function(){ return this.$store.getters.isLoggedIn}
},
methods: {
logout: function () {
this.$store.dispatch('logout')
.then(() => {
this.$router.push('/login')
})
}
},
}
</script>
当用户点击退出按钮时,我们其实在做两件事 — 计算用户验证的状态和分发vuex store里面的退出事件。在退出之后,我们利用 this.$router.push('/login'),切换用户到 login页面。当然你可以改变任何你想让用户跳转的地方。
就是这样了。让我们用vuex构建权限模块。
如果你读过以前的Setup Node.js Server **部分, 你应该注意到我们需要在本地存储用户权限token,同时,当用户被授予权限后,我们随时需要重新得到token以及用户信息。
首先, 让我们给vuex创建 store.js文件:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
status: '',
token: localStorage.getItem('token') || '',
user : {}
},
mutations: {
},
actions: {
},
getters : {
}
})
如果你注意到,我们同时引入了vue,vuex和axios,之后让vue使用vuex,这是因为它是很重要的一步。
我们已经定义了state的属性。现在vuex的state能够支持验证状态, jwt token以及用户信息。
Vuex actions里面主要是提交更改到vuex的store里面。我们将创建一个login 的action,它将使用服务器对用户进行身份验证,并向vuex存储提交用户凭据。打开./src/store.js文件,并添加下面到actions对象中:
login({commit}, user){
return new Promise((resolve, reject) => {
commit('auth_request')
axios({url: 'http://localhost:3000/login', data: user, method: 'POST' })
.then(resp => {
const token = resp.data.token
const user = resp.data.user
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
},
登录action通过vuex commit验证,我们将用它进行触发更改。vuex store里面能记录这些更改的变化。
我们正在调用服务器的登录路径并返回必要的数据。我们在本地存储token,之后通过auth_success来更新存储用户信息和token。在这一点上,我们也在头部设置了axios。
我们可以在vuex store中存储token,但是如果用户离开我们的应用,所有在vuex里面的存储都将消失。为了确保用户在有效时间内不用再重复登录,我们只能将token进行本地存储。
重要的是你知道这些是如何工作的,这样你就能决定你到底想要实现什么。
我们返回一个promise,这样我们能在用户登录完成后,做出响应。
像 login 事件, the register 事件是同一种工作方式。在相同的文件中,添加下面的到actions对象里面:
register({commit}, user){
return new Promise((resolve, reject) => {
commit('auth_request')
axios({url: 'http://localhost:3000/register', data: user, method: 'POST' })
.then(resp => {
const token = resp.data.token
const user = resp.data.user
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error', err)
localStorage.removeItem('token')
reject(err)
})
})
},
它与login 事件工作方式很像,。称之为有共同的mutators的 login 和register ,具有相同的目标——让用户进入系统。
我们希望用户能够退出系统,同时,我们希望销毁上一次验证的会话数据。在同一个actions对象中,添加下面:
logout({commit}){
return new Promise((resolve, reject) => {
commit('logout')
localStorage.removeItem('token')
delete axios.defaults.headers.common['Authorization']
resolve()
})
}
现在,当用户点击退出时,我们将移除之前在 axios头部设置的jwt token 。他们现在将无法执行需要token的事务。
像我之前提到的,mutators是被用来改变vuex store的状态。让我们在应用中给用过的mutators定义。在mutators对象中,添加下面的:
mutations: {
auth_request(state){
state.status = 'loading'
},
auth_success(state, token, user){
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state){
state.status = 'error'
},
logout(state){
state.status = ''
state.token = ''
},
},
我们使用getter来获取vuex状态中的属性值。在这种情况下,getter的作用是将应用程序数据与应用程序逻辑分离,并确保我们不会泄露敏感信息。
添加下面的到getters 对象中:
getters : {
isLoggedIn: state => !!state.token,
authStatus: state => state.status,
}
你会同意我的观点,这是一种更简洁的访问存储数据的方式
这篇文章的整个目的是实现身份验证,让没有权限的用户看不到某些页面。为了实现这个,我们需要知道用户想要访问的页面,以及当用户被授权时,我们有一定的方法来检验它。我们同时需要一定的方式,如果某些页面,授权或者未授权的用户可以单独或者同时访问的。这些都是很重要的考虑条件,幸运地是,我们可以通过vue-router来说实现。
打开 ./src/router.js 文件,并引入我们需要的这些:
import Vue from 'vue'
import Router from 'vue-router'
import store from './store.js'
import Home from './views/Home.vue'
import About from './views/About.vue'
import Login from './components/Login.vue'
import Secure from './components/Secure.vue'
import Register from './components/Register.vue'
Vue.use(Router)
正如你看到的这样,我们已经引入vue,vue-router和我们创建的vuex。我们同时还引入了定义的所有组件,并设置vue中使用路由。
让我们定义路由:
[...]
let router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/register',
name: 'register',
component: Register
},
{
path: '/secure',
name: 'secure',
component: Secure,
meta: {
requiresAuth: true
}
},
{
path: '/about',
name: 'about',
component: About
}
]
})
export default router
我们路由的定义是很普遍的。对于需要权限验证的路由,我们需要增加额外的数据,确保当用户访问它时,我们可以识别它。这是添加到路由定义中的元属性的本质。如果你想问_”我可以添加更过的数据给元数据并使用它吗?”,我很坚定的告诉你,这是绝对的
我们有自己的路由定义。现在,让我们检验未授权访问并采取行动。在 router.js文件中,添加下面的在 export default router之前:
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.requiresAuth)) {
if (store.getters.isLoggedIn) {
next()
return
}
next('/login')
} else {
next()
}
})
从这篇文章,通过使用vue router来进行身份验证,你可以回想一下我们这里有一个非常复杂的机制,它变得非常大,变得非常混乱。vuex已经帮我们简化了它,我们可以继续给路由添加任何条件。在我们的vuex存储中,我们可以定义操作来检查这些条件并获取返回它们的值。
因为我们在本地存储token,它可以一直保留着。这意味着无论何时,我们打开自己的应用,它可以自动的验证用户,即使token已经过期失效。最多的情况是,我们的请求会因为无效token而持续失败。这对于用户是个不好的体验。
现在, 打开./src/App.vue 文件并在script里面,添加下面的:
export default {
[...]
created: function () {
this.$http.interceptors.response.use(undefined, function (err) {
return new Promise(function (resolve, reject) {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
this.$store.dispatch(logout)
}
throw err;
});
});
}
}
我们截获axios请求,已确定是否获取到401未授权响应。如果这么做,我们分发 logout事件,那么用户获得退出应用。这会让用户跳转到之前设计的 login页面,这样他们可以再次登录。
我赞同这样会提升用户体验 .
从以前的文章来看,您可以看到,基于vuex的引入,我们目前的应用程序发生了重大变化。现在,我们不依赖于一直检查token,不管到哪里都有混乱的条件。我们可以简单地使用vuex存储来管理权限,并且只需使用几行代码检查应用程序中的状态。
我希望这可以帮助您建立更好的应用。
原文链接: scotch.io
翻译来源:zcfy.cc
在学习Vuex之前,先了解一下“单向数据流”。Vuex核心就是它的store,其中,有三个重要的部分,State:通过它存取多个组件共享的数据。Mutations:可以改变State中的数据,Actions:提交mutation,可以包含任意异步操作这一步不是必要的。
Vuex是一个专门为Vue.js框架设计的、用于对Vue.js应用程序进行状态管理的库,它借鉴了Flux、redux的基本思想,将共享的数据抽离到全局,以一个单例存放,同时利用Vue.js的响应式机制来进行高效的状态管理与更新。
主要目的是学会使用koa框架搭建web服务,从而提供一些后端接口,供前端调用。搭建这个环境的目的是: 前端工程师在跟后台工程师商定了接口但还未联调之前,涉及到向后端请求数据的功能能够走前端工程师自己搭建的http路径
vuex 规定更改 state 的唯一方法是提交 mutation,主要是为了能用 devtools 追踪状态变化。那么,提交 mutation 除了最主要的更改 state,它还做了其它一些什么事情呢,让我们来一探究竟。
已知Vuex中通过actions提交mutations要通过context.commit(mutations,object)的方式来完成,然而commit中只能传入两个参数,第一个就是mutations,第二个就是要传入的参数
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数 mutation 是同步执行,不是异步执行。
其实很简单,因为store里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值。一种是state里的数据全部是通过请求来触发action或mutation来改变
首先在 vue 2.0+ 你的vue-cli项目中安装 vuex :然后 在src文件目录下新建一个名为store的文件夹,为方便引入并在store文件夹里新建一个index.js,里面的内容如下:接下来,在 main.js里面引入store,然后再全局注入一下
开始尝试学习使用vue,是因为此前总是遇到页面逻辑数据与视图的一致性问题.在使用vue之前,我们使用jQuery插件的时候,一桩麻烦事就是既要在每个数据变更后,写代码去改变视图,又要考虑html上各种输入
随着Vue应用程序的大小增加,Vuex Store中的actions和mutations也会增加。本文,我们将介绍如何将其减少到易于管理的东西。Vuex是vue.js应用程序的状态管理模式+库。它充当应用程序中所有组件的集中存储
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!