溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用Vuex解決Vue中的身份驗(yàn)證問題

發(fā)布時(shí)間:2020-10-17 14:25:02 來源:腳本之家 閱讀:112 作者:婷風(fēng) 欄目:web開發(fā)

傳統(tǒng)方式中,許多人使用本地存儲(chǔ),來管理通過客戶端驗(yàn)證生成的tokens。一個(gè)大問題是如何有更好的方式,來管理驗(yàn)證tokens,從而允許我們來存儲(chǔ)更大的用戶信息。

這就是Vuex的作用。 Vuex為Vue.js應(yīng)用管理狀態(tài).。對(duì)于應(yīng)用中所有的組件來說,它被當(dāng)做中央存儲(chǔ),并用規(guī)則確保狀態(tài)只能以可預(yù)見的方式改變。

對(duì)于經(jīng)常檢查本地存儲(chǔ)來說,聽起來是個(gè)更好的選擇?讓我們一起來探索下吧。

建立應(yīng)用模塊

對(duì)于這個(gè)項(xiàng)目,我們想創(chuàng)建一個(gè)使用vuex和vue-router的vue應(yīng)用。我們會(huì)使用vue cli 3.0 來創(chuàng)建一個(gè)vue項(xiàng)目,并從選項(xiàng)中選擇路由和vuex。

執(zhí)行下面的命令開始創(chuàng)建:

$ vue create vue-auth

按照對(duì)話框的提示,添加必要的信息,并選擇我們需要的選項(xiàng),完成安裝。

下一步, 安裝axios:

$ npm install axios --save 

配置Axios

我們?cè)谠S多組件中都需要用到axios。讓我們?cè)谌终w來配置它,這樣當(dāng)我們需要它的時(shí)候,不用每次都去引入。

打開 ./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
}
[...]

現(xiàn)在,當(dāng)我們想在組件內(nèi)使用axios時(shí), 我們可以用this.$http ,這樣相當(dāng)于直接是axios。我們也可以在axios頭部給自己的token, 設(shè)置身份驗(yàn)證,這樣如果token是必需的,我們的請(qǐng)求將處于控制中。在這種方式下,當(dāng)我們想要發(fā)送請(qǐng)求時(shí),任何時(shí)候都不用設(shè)置token。

相關(guān)課程: Vue創(chuàng)建一個(gè)網(wǎng)上商店

完成之后,讓我們使用服務(wù)器來處理身份驗(yàn)證。

創(chuàng)建身份驗(yàn)證服務(wù)

我已經(jīng)寫過關(guān)于這個(gè),在我解釋如何用vue-router來解決身份驗(yàn)證時(shí)。仔細(xì)看看Setup Node.js Server 這個(gè)章節(jié)。

創(chuàng)建組件

登錄組件

創(chuàng)建Login.vue ./src/components 目錄下。 之后, 給登錄頁面添加模板:

<template>
 <div>
 <form class="login" @submit.prevent="login">
  <h2>Sign in</h2>
  <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>

當(dāng)你做完之后, 添加data屬性,將其綁定到HTML表單中:

[...]
<script>
 export default {
 data(){
  return {
  email : "",
  password : ""
  }
 },
 }
</script>

現(xiàn)在, 讓我們給登錄添加方法:

[...]
<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 來解決身份驗(yàn)證。我們可以在將actions細(xì)化到回調(diào)里面,這樣就可以在自己的組件里面做一些很酷的事情了。

注冊(cè)組件

跟login組件類似,那我們給注冊(cè)用戶弄一個(gè)了。在組件目錄里面創(chuàng)建Register.vue ,并將下面的添加進(jìn)去:

<template>
 <div>
 <h5>Register</h5>
 <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>

現(xiàn)在,讓我們添加方法進(jìn)去:

[...]
<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> 

安全組件

讓我們創(chuàng)建一個(gè)普通的組件,它在用戶通過驗(yàn)證后會(huì)顯示。文件命名為Secure.vue,并添加下面的進(jìn)去:

<template>
 <div>
 <h2>This page is protected by auth</h2>
 </div>
</template>

更新App組件

打開./src/App.vue 文件,并添加下面的進(jìn)去:

<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>

如果用戶登錄進(jìn)去后,你能看到關(guān)聯(lián)的Logout了 嗎?很好。

現(xiàn)在,讓我們給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>

當(dāng)用戶點(diǎn)擊退出按鈕時(shí),我們其實(shí)在做兩件事 — 計(jì)算用戶驗(yàn)證的狀態(tài)和分發(fā)vuex store里面的退出事件。在退出之后,我們利用 this.$router.push('/login'),切換用戶到 login頁面。當(dāng)然你可以改變?nèi)魏文阆胱層脩籼D(zhuǎn)的地方。

就是這樣了。讓我們用vuex構(gòu)建權(quán)限模塊。

Vuex權(quán)限模塊

如果你讀過以前的Setup Node.js Server **部分, 你應(yīng)該注意到我們需要在本地存儲(chǔ)用戶權(quán)限token,同時(shí),當(dāng)用戶被授予權(quán)限后,我們隨時(shí)需要重新得到token以及用戶信息。

首先, 讓我們給vuex創(chuàng)建 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 : {
 }
})

如果你注意到,我們同時(shí)引入了vue,vuex和axios,之后讓vue使用vuex,這是因?yàn)樗呛苤匾囊徊健?/p>

我們已經(jīng)定義了state的屬性。現(xiàn)在vuex的state能夠支持驗(yàn)證狀態(tài), jwt token以及用戶信息。

創(chuàng)建Vuex登錄事件

Vuex actions里面主要是提交更改到vuex的store里面。我們將創(chuàng)建一個(gè)login 的action,它將使用服務(wù)器對(duì)用戶進(jìn)行身份驗(yàn)證,并向vuex存儲(chǔ)提交用戶憑據(jù)。打開./src/store.js文件,并添加下面到actions對(duì)象中:

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驗(yàn)證,我們將用它進(jìn)行觸發(fā)更改。vuex store里面能記錄這些更改的變化。

我們正在調(diào)用服務(wù)器的登錄路徑并返回必要的數(shù)據(jù)。我們?cè)诒镜卮鎯?chǔ)token,之后通過auth_success來更新存儲(chǔ)用戶信息和token。在這一點(diǎn)上,我們也在頭部設(shè)置了axios 。

我們可以在vuex store中存儲(chǔ)token,但是如果用戶離開我們的應(yīng)用,所有在vuex里面的存儲(chǔ)都將消失。為了確保用戶在有效時(shí)間內(nèi)不用再重復(fù)登錄,我們只能將token進(jìn)行本地存儲(chǔ)。

重要的是你知道這些是如何工作的,這樣你就能決定你到底想要實(shí)現(xiàn)什么。

我們返回一個(gè)promise,這樣我們能在用戶登錄完成后,做出響應(yīng)。

創(chuàng)建Vuex注冊(cè)事件

像 login 事件, the register 事件是同一種工作方式。在相同的文件中,添加下面的到actions對(duì)象里面:

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 ,具有相同的目標(biāo)——讓用戶進(jìn)入系統(tǒng)。

創(chuàng)建Vuex退出事件

我們希望用戶能夠退出系統(tǒng),同時(shí),我們希望銷毀上一次驗(yàn)證的會(huì)話數(shù)據(jù)。在同一個(gè)actions對(duì)象中,添加下面:

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

現(xiàn)在,當(dāng)用戶點(diǎn)擊退出時(shí),我們將移除之前在 axios頭部設(shè)置的jwt token 。他們現(xiàn)在將無法執(zhí)行需要token的事務(wù)。

創(chuàng)建Mutations

像我之前提到的,mutators是被用來改變vuex store的狀態(tài)。讓我們?cè)趹?yīng)用中給用過的mutators定義。在mutators對(duì)象中,添加下面的:

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 = ''
 },
},

創(chuàng)建Getters

我們使用getter來獲取vuex狀態(tài)中的屬性值。在這種情況下,getter的作用是將應(yīng)用程序數(shù)據(jù)與應(yīng)用程序邏輯分離,并確保我們不會(huì)泄露敏感信息。

添加下面的到getters 對(duì)象中:

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

你會(huì)同意我的觀點(diǎn),這是一種更簡(jiǎn)潔的訪問存儲(chǔ)數(shù)據(jù)的方式☺️.

在Auth后面隱藏頁面

這篇文章的整個(gè)目的是實(shí)現(xiàn)身份驗(yàn)證,讓沒有權(quán)限的用戶看不到某些頁面。為了實(shí)現(xiàn)這個(gè),我們需要知道用戶想要訪問的頁面,以及當(dāng)用戶被授權(quán)時(shí),我們有一定的方法來檢驗(yàn)它。我們同時(shí)需要一定的方式,如果某些頁面,授權(quán)或者未授權(quán)的用戶可以單獨(dú)或者同時(shí)訪問的。這些都是很重要的考慮條件,幸運(yùn)地是,我們可以通過vue-router來說實(shí)現(xiàn)。

定義路由給授權(quán)和未授權(quán)的頁面

打開 ./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)

正如你看到的這樣,我們已經(jīng)引入vue,vue-router和我們創(chuàng)建的vuex。我們同時(shí)還引入了定義的所有組件,并設(shè)置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

 我們路由的定義是很普遍的。對(duì)于需要權(quán)限驗(yàn)證的路由,我們需要增加額外的數(shù)據(jù),確保當(dāng)用戶訪問它時(shí),我們可以識(shí)別它。這是添加到路由定義中的元屬性的本質(zhì)。如果你想問_”我可以添加更過的數(shù)據(jù)給元數(shù)據(jù)并使用它嗎?”,我很堅(jiān)定的告訴你,這是絕對(duì)的😁。

解決未授權(quán)訪問示例

我們有自己的路由定義?,F(xiàn)在,讓我們檢驗(yàn)未授權(quán)訪問并采取行動(dòng)。在 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來進(jìn)行身份驗(yàn)證,你可以回想一下我們這里有一個(gè)非常復(fù)雜的機(jī)制,它變得非常大,變得非?;靵y。vuex已經(jīng)幫我們簡(jiǎn)化了它,我們可以繼續(xù)給路由添加任何條件。在我們的vuex存儲(chǔ)中,我們可以定義操作來檢查這些條件并獲取返回它們的值。

解決Token過期示例

因?yàn)槲覀冊(cè)诒镜卮鎯?chǔ)token,它可以一直保留著。這意味著無論何時(shí),我們打開自己的應(yīng)用,它可以自動(dòng)的驗(yàn)證用戶,即使token已經(jīng)過期失效。最多的情況是,我們的請(qǐng)求會(huì)因?yàn)闊o效token而持續(xù)失敗。這對(duì)于用戶是個(gè)不好的體驗(yàn)。

現(xiàn)在, 打開./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請(qǐng)求,已確定是否獲取到401未授權(quán)響應(yīng)。如果這么做,我們分發(fā) logout 事件,那么用戶獲得退出應(yīng)用。這會(huì)讓用戶跳轉(zhuǎn)到之前設(shè)計(jì)的 login頁面,這樣他們可以再次登錄。

我贊同這樣會(huì)提升用戶體驗(yàn) ☺️.

結(jié)束

從以前的文章來看,您可以看到,基于vuex的引入,我們目前的應(yīng)用程序發(fā)生了重大變化?,F(xiàn)在,我們不依賴于一直檢查token,不管到哪里都有混亂的條件。我們可以簡(jiǎn)單地使用vuex存儲(chǔ)來管理權(quán)限,并且只需使用幾行代碼檢查應(yīng)用程序中的狀態(tài)。

以上所述是小編給大家介紹的使用Vuex解決Vue中的身份驗(yàn)證問題,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI