一. 安装vuex及永久化vuex)
npm i vuex
npm install --save vuex-persistedstate
在 src 目录下 创建 "store" 文件夹, 并在文件夹下创建index.js文件, 代码如下:
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, //状态管理 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文件引入
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下创建login.vue组件, 代码如下:
<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 });//跳转到来源页面 } } else{ this.$message({ message: '账号密码不正确', type: 'warning', offset:200 }); } }) } } } </script> <style> .form{ width:300px; margin: 20px auto; } </style>
四. 创建安全退出文件Exit.vue
<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: "/"}); //此处写提示关闭后需要执行的函数 } }); } } </script>
五, 配置路由及导航守卫
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); //保存当前路径 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){ //验证有问题 // console.log("验证不通过"); localStorage.setItem("preRoute", router.currentRoute.fullPath) if(to.path == "/login" || to.path == "/exit"){ next(); } else{ next("/login"); } } else{ // console.log("验证通过"); next(); } }).catch(e => { }) } } }) export default router
六. 后台登陆及token验证
public function loginCheck(){ $post = $this->request->post("params"); // halt($post); //模拟比较, 实际应用中通常 从数据库中查询比对 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进行验证签名 $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端解决跨域操作的方法,在入口文件中加入以下内容:
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");
效果如下: