使用Vuex解决Vue中的身份验证问题


Posted in Javascript onSeptember 28, 2018

传统方式中,许多人使用本地存储,来管理通过客户端验证生成的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

我们在许多组件中都需要用到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>

更新App组件

打开./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构建权限模块。

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登录事件

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,这样我们能在用户登录完成后,做出响应。

创建Vuex注册事件

像 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 ,具有相同的目标——让用户进入系统。

创建Vuex退出事件

我们希望用户能够退出系统,同时,我们希望销毁上一次验证的会话数据。在同一个actions对象中,添加下面:

logout({commit}){
 return new Promise((resolve, reject) => {
 commit('logout')
 localStorage.removeItem('token')
 delete axios.defaults.headers.common['Authorization']
 resolve()
 })
}

现在,当用户点击退出时,我们将移除之前在 axios头部设置的jwt token 。他们现在将无法执行需要token的事务。

创建Mutations

像我之前提到的,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 = ''
 },
},

创建Getters

我们使用getter来获取vuex状态中的属性值。在这种情况下,getter的作用是将应用程序数据与应用程序逻辑分离,并确保我们不会泄露敏感信息。

添加下面的到getters 对象中:

getters : {
 isLoggedIn: state => !!state.token,
 authStatus: state => state.status,
}

你会同意我的观点,这是一种更简洁的访问存储数据的方式☺️.

在Auth后面隐藏页面

这篇文章的整个目的是实现身份验证,让没有权限的用户看不到某些页面。为了实现这个,我们需要知道用户想要访问的页面,以及当用户被授权时,我们有一定的方法来检验它。我们同时需要一定的方式,如果某些页面,授权或者未授权的用户可以单独或者同时访问的。这些都是很重要的考虑条件,幸运地是,我们可以通过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已经过期失效。最多的情况是,我们的请求会因为无效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存储来管理权限,并且只需使用几行代码检查应用程序中的状态。

以上所述是小编给大家介绍的使用Vuex解决Vue中的身份验证问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
不要小看注释掉的JS 引起的安全问题
Dec 27 Javascript
JS 类型转换常见方法小结
May 31 Javascript
js根据给定的日期计算当月有多少天实现思路及代码
Feb 25 Javascript
js正文内容高亮效果的实现方法
Jun 30 Javascript
JS+CSS实现感应鼠标渐变显示DIV层的方法
Feb 20 Javascript
Javascript实现飞动广告效果的方法
May 25 Javascript
JS中Attr的用法详解
Oct 09 Javascript
JS实现字符串翻转的方法分析
Aug 31 Javascript
Angularjs Ng_repeat中实现复选框选中并显示不同的样式方法
Sep 12 Javascript
详解key在Vue列表渲染时究竟起到了什么作用
Apr 20 Javascript
koa router 多文件引入的方法示例
May 22 Javascript
node创建Vue项目步骤详解
Mar 06 Javascript
js限制输入框只能输入数字(onkeyup触发)
Sep 28 #Javascript
js限制input只能输入有效的数字(第一个不能是小数点)
Sep 28 #Javascript
js实现点击展开隐藏效果(实例代码)
Sep 28 #Javascript
javascript中toFixed()四舍五入使用方法详解
Sep 28 #Javascript
对vue中v-if的常见使用方法详解
Sep 28 #Javascript
总结javascript三元运算符知识点
Sep 28 #Javascript
2种在vue项目中使用百度地图的简单方法
Sep 28 #Javascript
You might like
各种咖啡的英文名子是什么
2021/03/03 新手入门
PHP 获取文件权限函数介绍
2013/07/11 PHP
php猴子选大王问题解决方法
2015/05/12 PHP
Yii 访问 Gii(脚手架)时出现 403 错误
2018/06/06 PHP
laravel 模型查询按照whereIn排序的示例
2019/10/16 PHP
用Javscript实现表单复选框的全选功能
2007/05/25 Javascript
JQuery 1.4 中的Ajax问题
2010/01/23 Javascript
IE8下关于querySelectorAll()的问题
2010/05/13 Javascript
jquery中防刷IP流量软件影响统计的一点对策
2011/07/10 Javascript
JavaScript高级程序设计 学习笔记 js高级技巧
2011/09/20 Javascript
基于jquery的bankInput银行卡账号格式化
2012/08/22 Javascript
js 动态修改css文件用到了cssRule
2014/08/20 Javascript
js实现按一下删除键删除整个单词附demo
2014/09/05 Javascript
jQuery动画效果实现图片无缝连续滚动
2016/01/12 Javascript
jquery分页插件jquery.pagination.js实现无刷新分页
2016/04/01 Javascript
从零开始最小实现react服务器渲染详解
2018/01/26 Javascript
vue 组件内获取actions的response方式
2019/11/08 Javascript
vue离开当前页面触发的函数代码
2020/09/01 Javascript
python根据出生年份简单计算生肖的方法
2015/03/27 Python
使用py2exe在Windows下将Python程序转为exe文件
2016/03/04 Python
python snownlp情感分析简易demo(分享)
2017/06/04 Python
Python 实现两个列表里元素对应相乘的方法
2018/11/14 Python
python实现定时压缩指定文件夹发送邮件
2020/12/22 Python
JD Sports德国官网:英国领先的运动鞋和运动服饰零售商
2018/02/26 全球购物
美国婴儿和儿童服装购物网站:PatPat
2020/10/01 全球购物
单位提档介绍信
2014/01/17 职场文书
股东出资证明书范例
2014/10/04 职场文书
2014年银行员工工作总结
2014/11/12 职场文书
学校党员干部承诺书
2015/05/04 职场文书
学校运动会加油词
2015/07/18 职场文书
优秀教师工作总结2015
2015/07/22 职场文书
2015少先队大队辅导员工作总结
2015/07/24 职场文书
JavaScript实现复选框全选功能
2021/04/11 Javascript
mysql的数据压缩性能对比详情
2021/11/07 MySQL
MSSQL基本语法操作
2022/04/11 SQL Server
Three.js实现雪糕地球的使用示例详解
2022/07/07 Javascript