一. 安裝vuex及永久化vuex)
npm i vuex
npm install --save vuex-persistedstate
在 src 目錄下 創(chuàng)建 "store" 文件夾, 并在文件夾下創(chuàng)建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 | import Vue from 'vue' ; import Vuex from 'vuex' ; import createPersistedState from 'vuex-persistedstate' ; Vue.use(Vuex); const state = { 'token' : '' }; const mutations = { changeToken(state,params){ state.token = params; } }; const store = new Vuex.Store({ plugins:[createPersistedState()], state : state, //狀態(tài)管理 mutations:mutations, //修改state modules:{} //模塊 }); export default store; //main.js文件引入 import store from './store' ; |
二. 安裝Element組件 及axios組件
npm i element-ui -S
npm install axios --save
main.js文件引入
1 2 3 4 5 6 7 8 9 10 11 12 13 | import ElementUI from 'element-ui' ; import 'element-ui/lib/theme-chalk/index.css' ; Vue.use(ElementUI); import axios from 'axios' ; axios.defaults.baseURL= ' new Vue({ router, store, //注入,組件中可以使用 this.$store 獲取 render: h => h(App) }).$mount(' #app'); |
三. views下創(chuàng)建login.vue組件, 代碼如下:
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | <template> <div> <Header></Header> <el-form ref= "form" label-width= "80px" class= "form" > <el-form-item label= "用戶名" > <el-input v-model= "form.username" clearable></el-input> </el-form-item> <el-form-item label= "密碼" > <el-input v-model= "form.userpwd" show-password></el-input> </el-form-item> <el-form-item> <el-button type= "primary" @click= "login" >登陸</el-button> <el-button>取消</el-button> </el-form-item> </el-form> </div> </template> <script> console.log(localStorage.getItem( 'preRoute' )); import Header from "@/components/Header" export default { data() { return { form: { username: '' , userpwd : '' }, } }, components:{ Header }, methods:{ login(){ if ( this .form.username == '' ){ this .$message({ message: '用戶名不能為空' , type: 'warning' ,offset:200}); return false ; } if ( this .form.userpwd == '' ){ this .$message({ message: '用戶密碼不能為空' , type: 'warning' ,offset:200}); return false ; } // console.log(this.form); // return ; this .axios.post( "loginCheck" ,{params: this .form}).then(res=>{ let _this = this ; if (res.data.code == 1){ this .$store.commit( "changeToken" ,res.data.token); this .$message({ message: '登陸成功' , type: 'success' , offset:200, onClose:()=>{ // Object.keys(_this.data).forEach(key=>{_this.data[key]=''}) } }); const curr = localStorage.getItem( 'preRoute' ) if (curr == null ) { this .$router.push({ path: "/" }); } else { this .$router.push({ path: curr }); //跳轉(zhuǎn)到來源頁面 } } else { this .$message({ message: '賬號密碼不正確' , type: 'warning' , offset:200 }); } }) } } } </script> <style> .form{ width:300px; margin: 20px auto; } </style> |
四. 創(chuàng)建安全退出文件Exit.vue
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 | <template> <div> <Header></Header> </div> </template> <script> import Header from "@/components/Header" export default { components:{ Header }, mounted(){ this .$store.commit( "changeToken" , "" ); this .$message({ message: '安全退出' , type: 'success' , offset:200, onClose:()=>{ this .$router.push({ path: "/" }); //此處寫提示關(guān)閉后需要執(zhí)行的函數(shù) } }); } } </script> |
五, 配置路由及導(dǎo)航守衛(wèi)
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import Store from '../store' import axios from 'axios' ; Vue.use(VueRouter) const routes = [ { path: '/' , name: 'Home' , component: Home, meta: {login_require: true } }, { path: '/contact' , name: 'Cantact' , component:()=>import( '../views/Contact.vue' ), meta: {login_require: true } }, { path: '/message' , name: 'Message' , component:()=>import( '../views/Message.vue' ), meta: {login_require: true } }, { path: '/about' , name: 'About' , component:()=>import( '../views/About.vue' ), meta: {login_require: true } }, { path: '/news' , name: 'News' , component:()=>import( "../views/News.vue" ), meta: {login_require: true } }, { path: '/newsdetail' , name: 'Newsdetail' , component:()=>import( "../views/Newsdetail.vue" ), meta: {login_require: true } }, { path: '/vuexx' , name: 'Vuexx' , component:() => import( '../views/Vuexx.vue' ), meta: {login_require: true } }, { path: '/vuea' , name: 'Vuea' , component:() => import( '../views/Vuea.vue' ), meta: {login_require: true } }, { path: '/eleform' , name: 'Eleform' , component:()=> import( '../views/Eleform.vue' ), meta: {login_require: true } }, { path: '/mysecret' , name: 'Mysecret' , component:()=> import( '../views/mysecret.vue' ), meta: {login_require: false } }, { path: '/login' , name: "Login" , component:()=> import( '../views/login.vue' ), meta: {login_require: true } }, { path: '/exit' , name: "Exit" , component:()=> import( '../views/Exit.vue' ), meta: {login_require: true } } ] const router = new VueRouter({ routes }) router.beforeEach((to,from,next)=>{ let token = Store.state.token; if ((to.matched.some( function (item) { return item.meta.login_require }))) { next(); } else { if (token == "" ){ //沒有得到token, 所以去登陸 localStorage.setItem( "preRoute" , router.currentRoute.fullPath); //保存當(dāng)前路徑 if (to.path == "/login" || to.path == "/exit" ){ next(); } else { next( "/login" ); } } else { //有了token值, 然后判斷是否是正確的, 有沒有過期等 axios({ method: 'get' , url: "http://ggqvue.cn/vue/jwtTokenVerify" , headers: { 'Authorization' : token } //params:{token:token} }).then(res => { if (res.data.code == 2){ //驗(yàn)證有問題 // console.log("驗(yàn)證不通過"); localStorage.setItem( "preRoute" , router.currentRoute.fullPath) if (to.path == "/login" || to.path == "/exit" ){ next(); } else { next( "/login" ); } } else { // console.log("驗(yàn)證通過"); next(); } }). catch (e => { }) } } }) export default router |
六. 后臺登陸及token驗(yàn)證
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 | public function loginCheck(){ $post = $this ->request->post( "params" ); // halt($post); //模擬比較, 實(shí)際應(yīng)用中通常 從數(shù)據(jù)庫中查詢比對 if ( $post [ "username" ] == "admin" && $post [ "userpwd" ] == "123456" ){ $payload =[ 'iss' => '莊子' , 'iat' =>time(), 'exp' =>time()+7200, 'nbf' =>time(), 'sub' => '用戶登陸操作' , 'jti' =>md5(uniqid( 'JWT' ).time()), "username" => $post [ "username" ] ]; $token =\Jwt::getToken( $payload ); return json([ "code" =>1, "mes" => "登陸成功" , "token" => $token ]); } else { return json([ "code" =>2, "mes" => "登陸失敗" ]); } } public function jwtTokenVerify(){ $token = $this ->request->header( "Authorization" ); //對token進(jìn)行驗(yàn)證簽名 $result = \Jwt::verifyToken( $token ); if ( $result [ "code" ] == 1){ return json([ "code" =>1, "mes" => "success" , "username" => $result [ "payload" ][ "username" ]]); } else { return json([ "code" =>2, "mes" => "fail" ]); } } |
注意: php端解決跨域操作的方法,在入口文件中加入以下內(nèi)容:
1 2 3 | header( "Access-Control-Allow-Origin:*" ); header( "Access-Control-Allow-Methods:GET, POST, OPTIONS, DELETE" ); header( "Access-Control-Allow-Headers:DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type, Accept-Language, Origin, Accept-Encoding,Authorization" ); |
效果如下: