使用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 相关文章推荐
yepnope.js 异步加载资源文件
Sep 08 Javascript
jQuery实现点击文本框弹出热门标签的提示效果
Nov 17 Javascript
删除javascript中注释语句的正则表达式
Jun 11 Javascript
javascript控制图片播放的实现代码
Jul 29 Javascript
用NODE.JS中的流编写工具是要注意的事项
Mar 01 Javascript
浅谈JS原型对象和原型链
Mar 02 Javascript
jQuery的层级查找方式分析
Jun 16 Javascript
AngularJS中watch监听用法分析
Nov 04 Javascript
JavaScript实现自定义媒体播放器方法介绍
Jan 03 Javascript
Vue+Element使用富文本编辑器的示例代码
Aug 14 Javascript
微信小程序自定义多选事件的实现代码
May 17 Javascript
JS图片懒加载的优点及实现原理
Jan 10 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
function.inc.php超越php
2006/12/09 PHP
优化PHP代码技巧的小结
2013/06/02 PHP
PHP使用递归算法无限遍历数组示例
2017/01/13 PHP
PHP 进度条函数的简单实例
2017/09/19 PHP
PHP实现腾讯短网址生成api接口实例
2020/12/08 PHP
js实现DIV的一些简单控制
2007/06/04 Javascript
jQuery live
2009/05/15 Javascript
javascript实现上传图片并预览的效果实现代码
2011/04/11 Javascript
图片在浏览器中底部对齐 解决方法之一
2011/11/30 Javascript
jQuery动画效果animate和scrollTop结合使用实例
2014/04/02 Javascript
javascript正则表达式定义(语法)总结
2016/01/08 Javascript
实例讲解javascript注册事件处理函数
2016/01/09 Javascript
Node.js服务器环境下使用Mock.js拦截AJAX请求的教程
2016/05/23 Javascript
javascript比较语义化版本号的实现代码
2016/09/09 Javascript
jQuery上传插件webupload使用方法
2017/08/01 jQuery
Vue Cli与BootStrap结合实现表格分页功能
2017/08/18 Javascript
Node.js中环境变量process.env的一些事详解
2017/10/26 Javascript
jQuery中的$是什么意思及 $. 和 $().的区别
2018/04/20 jQuery
vux-scroller实现移动端上拉加载功能过程解析
2019/10/08 Javascript
基于js实现复制内容到操作系统粘贴板过程解析
2019/10/11 Javascript
keep-Alive搭配vue-router实现缓存页面效果的示例代码
2020/06/24 Javascript
Windows上配置Emacs来开发Python及用Python扩展Emacs
2015/11/20 Python
[原创]python爬虫(入门教程、视频教程)
2018/01/08 Python
Python利用itchat库向好友或者公众号发消息的实例
2019/02/21 Python
上海奥佳笔试题面试题
2016/11/16 面试题
顺丰快递Java软件工程师面试题
2015/07/31 面试题
银行贷款承诺书
2014/03/29 职场文书
师德演讲稿范文
2014/05/06 职场文书
给校长的一封检讨书
2014/09/20 职场文书
工作失误检讨书范文
2015/01/26 职场文书
集结号观后感
2015/06/08 职场文书
创业计划书之淘宝网店
2019/10/08 职场文书
在pycharm中无法import所安装的库解决方案
2021/05/31 Python
详解Python中*args和**kwargs的使用
2022/04/07 Python
Golang解析JSON对象
2022/04/30 Golang