一. 安装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");效果如下:


