使用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 相关文章推荐
推荐一些非常不错的javascript学习资源站点
Aug 29 Javascript
Javascript 各浏览器的 Javascript 效率对比
Jan 23 Javascript
document.getElementBy(&quot;id&quot;)与$(&quot;#id&quot;)有什么区别
Sep 22 Javascript
getAsDataURL在Firefox7.0下无法预览本地图片的解决方法
Nov 15 Javascript
JS版的date函数(和PHP的date函数一样)
May 12 Javascript
JS定义网页表单提交(submit)的方法
Mar 20 Javascript
纯JavaScript实现的兼容各浏览器的添加和移除事件封装
Mar 28 Javascript
详解vue.js下引入百度地图jsApi的两种方法
Jul 27 Javascript
vue单页缓存存在的问题及解决方案(小结)
Sep 25 Javascript
微信小程序实现通过双向滑动缩放图片大小的方法
Dec 30 Javascript
ES6中Set和Map用法实例详解
Mar 02 Javascript
Ajax请求超时与网络异常处理图文详解
May 23 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
PHP新手上路(九)
2006/10/09 PHP
PHP详细彻底学习Smarty
2008/03/27 PHP
PHP isset()与empty()的使用区别详解
2010/08/29 PHP
php阻止页面后退的方法分享
2014/02/17 PHP
PHP实现自动发送邮件功能代码(qq 邮箱)
2017/08/18 PHP
关于可运行代码无法正常执行的使用说明
2010/05/13 Javascript
javascript高级程序设计第二版第十二章事件要点总结(常用的跨浏览器检测方法)
2012/08/22 Javascript
JQuery获取样式中的background-color颜色值的问题
2013/08/20 Javascript
jquery easyui 结合jsp简单展现table数据示例
2014/04/18 Javascript
控制台报错object is not a function的解决方法
2014/08/24 Javascript
jQuery Ajax请求后台数据并在前台接收
2016/12/10 Javascript
JavaScript实现同一个页面打开多张图片
2016/12/29 Javascript
快速处理vue渲染前的显示问题
2018/03/05 Javascript
JS实现的判断方法、变量是否存在功能示例
2020/03/28 Javascript
详解操作虚拟dom模拟react视图渲染
2018/07/25 Javascript
超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法
2019/01/27 Javascript
Node Mongoose用法详解【Mongoose使用、Schema、对象、model文档等】
2020/05/13 Javascript
Python判断中文字符串是否相等的实例
2018/07/06 Python
只需7行Python代码玩转微信自动聊天
2019/01/27 Python
基于python cut和qcut的用法及区别详解
2019/11/22 Python
带你学习Python如何实现回归树模型
2020/07/16 Python
Python 如何实现访问者模式
2020/07/28 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
2021/01/15 Python
html5 localStorage本地存储_动力节点Java学院整理
2017/07/06 HTML / CSS
Html5自定义字体解决方法
2019/10/09 HTML / CSS
荷兰本土平价百货:HEMA
2017/10/23 全球购物
有影响力的人、名人和艺术家的官方商品:Represent
2019/11/26 全球购物
英国森林假期:Forest Holidays
2021/01/01 全球购物
C和C++经典笔试题附答案解析
2014/08/18 面试题
社区母亲节活动记录
2014/03/06 职场文书
校园歌咏比赛主持词
2014/03/18 职场文书
产品质量承诺书
2014/03/27 职场文书
法制教育观后感
2015/06/17 职场文书
2016党员发展对象培训心得体会
2016/01/08 职场文书
Python使用UDP实现720p视频传输的操作
2021/04/24 Python
vue使用节流函数的踩坑实例指南
2021/05/20 Vue.js