一. 安裝vuex及永久化vuex)
npm i vuex
npm install --save vuex-persistedstate
在 src 目錄下 創(chuàng)建 "store" 文件夾, 并在文件夾下創(chuàng)建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, //狀態(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文件引入
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組件, 代碼如下:
<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
<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)
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){ //驗證有問題
// 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);
//模擬比較, 實際應(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)行驗證簽名
$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)容:
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");效果如下:


