jwt+vuex+localStorage+beforeEach實現登入驗證
- 涉及到的知識點
① 後台介面的建置,以及解決跨域問題
② vuex的安裝以及是使用
③ 路由以及路由守衛的應用
④ axios網路請求
⑤ jsonwebtoken登入許可權驗證
⑥ localStorage 本地儲存
- 一 1. 構建專案vuex-anli,npm 新增login登入路由
router檔案
1 2 3 4 | {<!-- --> path:'/login', component:()=>import('../views/login') } |
- 2 .構建login頁面結構,安裝引入 axios
login檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <template> <div> 使用者名稱:<input type="text" v-model="username"><br> 密碼:<input type="text" v-model="pwd"> <button @click="login">登入</button> </div> </template> <script> import axios from 'axios' export default {<!-- --> data(){<!-- --> return{<!-- --> username:'', pwd:'' } }, methods:{<!-- --> login(){<!-- --> axios.post('http://localhost:5000/login','username='+this.usernamr +'&pwd='+this.pwd) .then(data=>{<!-- --> console.log(data); }) } } } </script> |
1 | npm i -S axios |
- 二 1. 建立server資料夾 構建後台
- post請求 引入bodyParser,引入cors後台解決跨域,在後台給定一個user物件,用來驗證登入是否正確,成功後回傳一個token值
token:jwt.sign({ })這裡面寫荷載資料,回傳一個隨機生成的id和username,在定義一個加密的字串 let jiami
server檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | let express = require('express'); let bodyParser = require('body-parser') let cors = require('cors'); let jwt = require('jsonwebtoken') let user = {<!-- --> username:'kevin', pwd:123 } let jiami ='idhsidhcsdjmsldmvpsdmdss' let app =express(); app.use(cors()) app.use(bodyParser.urlencoded({<!-- -->extended:false})) app.post('/login',(req,res)=>{<!-- --> if(req.body.username == user.username && req.body.pwd == user.pwd){<!-- --> res.send({<!-- --> msg:'success', token:jwt.sign({<!-- --> id:Math.floor(Math.random()*100000), username:user.username },jiami) }) }else{<!-- --> res.send({<!-- --> msg:'登入失敗' }) } }) app.listen(5000,function(){<!-- --> console.log(5000); }) |
1 2 | 安裝 express cors jsonwebtoken npm i -S express cors jsonwebtoken |
- 三 1. 進行登入許可權驗證,在router頁面,新增路由源訊息(登入狀態),使用路由前置守衛beforeEach,先看要跳轉的路徑,要不要有登入狀態,if(to.meta.islogin),看登入狀態islogin,如果有還為ture,那麼就從vuex中取得資料去,否則跳轉到登入頁面
router部分程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //路由前置守衛 router.beforeEach((to,from,next)=>{<!-- --> if(to.meta.islogin){<!-- --> //從vuex中取得登入狀態 let vuex_islogin=store.state.islogin if(vuex_islogin){<!-- --> next() }else{<!-- --> next('/login') } }else{<!-- --> next() } }) |
- 2.在store中,定義登入狀態islogin:false,以及改變登入狀態的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({<!-- --> state: {<!-- --> islogin:false }, mutations: {<!-- --> changeIsLogin(state){<!-- --> state.islogin=true } }, }) |
- 注意:路由還沒跳轉哪,在beforeEach中訪問不到this,這時需要把store用impo引進來
- 3 點選登入後判斷回傳的msg狀態,成功的話,呼叫store中的方法,改變state中定義的狀態值
- 4.把token儲存到本地,並回傳上一級
login部分程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | methods:{<!-- --> login(){<!-- --> axios.post('http://localhost:5000/login','username='+this.username +'&pwd='+this.pwd) .then(data=>{<!-- --> console.log(data); if(data.data.msg == 'success'){<!-- --> alert(data.data.msg) this.$store.commit('changeIsLogin') //把token儲存到本地 localStorage.setItem('vuex_login_token',data.data.token) //回傳上一層面 this.$router.back(); }else{<!-- --> alert(data.data.msg) } }) } } |
問題:清除快取後就又回到login頁面,從本地取得token,如果有說明登入過,然後把vuex的state更改為ture
main.js 部分程式碼
1 2 3 4 5 | //從本地取得token,如果有說明登入過,然後把vuex的state更改為ture let islogin = localStorage.getItem("vuex_login_token"); if(islogin){<!-- --> store.commit('changeIsLogin') } |
目錄結構:
完整程式碼如下
server.js程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | let express = require('express'); let bodyParser = require('body-parser') let cors = require('cors'); let jwt = require('jsonwebtoken') let user = {<!-- --> username:'kevin', pwd:123 } let jiami ='idhsidhcsdjmsldmvpsdmdss' let app =express(); app.use(cors()) app.use(bodyParser.urlencoded({<!-- -->extended:false})) app.post('/login',(req,res)=>{<!-- --> if(req.body.username == user.username && req.body.pwd == user.pwd){<!-- --> res.send({<!-- --> msg:'success', token:jwt.sign({<!-- --> id:Math.floor(Math.random()*100000), username:user.username },jiami) }) }else{<!-- --> res.send({<!-- --> msg:'登入失敗' }) } }) app.listen(5000,function(){<!-- --> console.log(5000); }) |
router index.js程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import store from '../store/index' Vue.use(VueRouter) const routes = [ {<!-- --> path: '/', name: 'Home', component: Home, meta:{<!-- --> islogin:true } }, {<!-- --> path: '/about', name: 'About', meta:{<!-- --> islogin:true }, // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') }, {<!-- --> path:'/login', component:()=>import('../views/login') } ] const router = new VueRouter({<!-- --> routes }) //路由前置守衛 router.beforeEach((to,from,next)=>{<!-- --> if(to.meta.islogin){<!-- --> //從vuex中取得登入狀態 let vuex_islogin=store.state.islogin if(vuex_islogin){<!-- --> next() }else{<!-- --> next('/login') } }else{<!-- --> next() } }) export default router |
store index.j』s程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({<!-- --> state: {<!-- --> islogin:false }, mutations: {<!-- --> changeIsLogin(state){<!-- --> state.islogin=true } }, }) |
login程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <template> <div> 使用者名稱:<input type="text" v-model="username"><br> 密碼:<input type="text" v-model="pwd"> <button @click="login">登入</button> </div> </template> <script> import axios from 'axios' export default {<!-- --> data(){<!-- --> return{<!-- --> username:'', pwd:'' } }, methods:{<!-- --> login(){<!-- --> axios.post('http://localhost:5000/login','username='+this.username +'&pwd='+this.pwd) .then(data=>{<!-- --> console.log(data); if(data.data.msg == 'success'){<!-- --> alert(data.data.msg) this.$store.commit('changeIsLogin') //把token儲存到本地 localStorage.setItem('vuex_login_token',data.data.token) //回傳上一層面 this.$router.back(); }else{<!-- --> alert(data.data.msg) } }) } } } </script> |
main.js程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false //從本地取得token,如果有說明登入過,然後把vuex的state更改為ture let islogin = localStorage.getItem("vuex_login_token"); if(islogin){<!-- --> store.commit('changeIsLogin') } new Vue({<!-- --> router, store, render: h => h(App) }).$mount('#app') |