jwt+vuex+localStorage+beforeEach实现登录验证
- 涉及到的知识点
① 后台接口的搭建,以及解决跨域问题
② vuex的安装以及是使用
③ 路由以及路由守卫的应用
④ axios网络请求
⑤ jsonwebtoken登录权限验证
⑥ localStorage 本地存储
- 一 1. 构建项目vuex-anli,npm 新增login登录路由
router文件
{
path:'/login',
component:()=>import('../views/login')
}
- 2 .构建login页面结构,安装引入 axios
login文件
<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>
npm i -S axios
- 二 1. 创建server文件夹 构建后台
- post请求 引入bodyParser,引入cors后台解决跨域,在后台给定一个user对象,用来验证登录是否正确,成功后返回一个token值
token:jwt.sign({ })这里面写荷载数据,返回一个随机生成的id和username,在定义一个加密的字符串 let jiami
server文件
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);
})
安装 express cors jsonwebtoken
npm i -S express cors jsonwebtoken
- 三 1. 进行登录权限验证,在router页面,添加路由源信息(登录状态),使用路由前置守卫beforeEach,先看要跳转的路径,要不要有登录状态,if(to.meta.islogin),看登录状态islogin,如果有还为ture,那么就从vuex中获取数据去,否则跳转到登录页面
router部分代码如下
//路由前置守卫
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,以及改变登录状态的方法
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部分代码
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 部分代码
//从本地获取token,如果有说明登陆过,然后把vuex的state更改为ture
let islogin = localStorage.getItem("vuex_login_token");
if(islogin){
store.commit('changeIsLogin')
}
目录结构:
完整代码如下
server.js代码
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代码
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代码
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代码
<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代码
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')