vue框架+axios实现登录守卫(验证token是否存在以及过期)
程序员文章站
2022-07-03 07:58:13
...
vue框架+axios实现登录守卫(token)
做项目的时候需要用到登录成功跳转到首页的功能,并且首页没有登录需要自动跳蛛到登录,这就要求设置axios,配置请求拦截器、响应拦截器。把学到的笔记记录并且下来,方便下次回忆。
首先前后端数据库服务器等我已经配置好了,单个页面都可以使用的。
这次用到了本地存储,当登录成功后,本地存储会保存token,实现跨域登录。当token失效后,会删除本地存储中的token,则需要跳转到登录页面。
这是服务器端的目录
这里是vue框架的目录
项目依赖
login.vue
<template>
<div class="login">
<el-form
:model="loginUser"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
class="loginUser"
>
<el-form-item label="手机号" prop="tel">
<el-input v-model="loginUser.tel" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="loginUser.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "login",
data: function() {
return {
loginUser: {
tel: "12323452345",
password: "123456"
//这里写成默认方便测试,可以自己清空,输入数据库的东西
},
rules: {
tel: [
{ required: true, message: "手机号不能为空", trigger: "blur" }, //required,必须不能为空
//blur,光标离开失去焦点
{ min: 11, max: 11, message: "手机号码必须是11位", trigger: "blur" }
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" }, //required,必须不能为空
//blur,光标离开失去焦点
{ min: 6, max: 6, message: "密码必须是6位", trigger: "blur" }
]
}
};
},
methods: {
submitForm(formName) {
//通过ref定位到form表单
this.$refs[formName].validate(valid => {
if (valid) {
alert("登录成功!");
this.$axios.post('http://localhost:3000/users/login',this.loginUser)
.then(res =>{
console.log('登录成功' ,res)
this.$router.push('/index');
})
.catch(err =>{
console.log(err)
})
} else {
console.log("提交失败!!");
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
};
</script>
<style lang="css" scoped>
.login {
width: 100%;
height: 100%;
background: url("../assets/980.jpg") no-repeat center center;
background-size: 100% 100%;
}
.loginUser {
width: 400px;
height: 380px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -200px;
margin-top: -190px;
border-radius: 5px;
background-color: #fff;
padding: 20px 50px 10px 10px;
}
</style>
这里是userController.js,userDao这里没什么需要更改的暂且不记
login: function (req, res) {
//接收用户请求传入的参数,并创建用户对象
var user = { tel: req.body.tel, password: req.body.password }
userDAO.getUserByTel(user.tel, function (err, results) {
if (err) {
res.status(500).json({ msg: '数据库错误,登录失败!' })
} else {
if (results == null || results.length != 1) {
res.status(200).json({ msg: '手机号不存在,登录失败!' })
} else {
bcrypt.compare(user.password, results[0].password, function (err, resPwd) {
// res == true
if (resPwd) {
//记录登录成功后的token ,expiresIn用的是10s,方便跳转验证
jwt.sign({ tel: user.tel }, 'privateKey', { expiresIn:10 }, function (err, token) {
console.log(token);
//注意token的固定格式“Bearer ”前缀
res.status(200).json({ msg: '登录成功!!', token: 'Bearer ' + token })
});
} else {
res.status(200).json({ msg: '密码错误,登录失败!!' })
}
});
}
}
})
},
当然需要配置目录config里面passport.js
//用于验证token的模块
var JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'privateKey';
function myPassport(passport){
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
//jwt_payload保存的是token生成时的对象
console.log(jwt_payload)
//通过验证后执行下一步
done(null,jwt_payload)
}));
}
module.exports = myPassport
首先app.js里面跨域请求需要的操作要有
这里的localhost:8080就是我vue请求跳转界面要用到的头部
需要注意的是,在Access-Control-Allow-Headers里面要添加Authorization,这个是处理401状态码要用到的东西。
//设置跨域请求的允许操作
app.all('*', function (req, res, next) {
// res.header('Access-Control-Allow-Origin', '*'); //针对所有请求用户都允许
res.header('Access-Control-Allow-Origin', 'http://localhost:8080'); //针对指定的请求用户允许,其他用户禁止访问
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.header('Access-Control-Allow-Methods', '*');
res.header('Access-Control-Allow-Credentials', 'true');
next()
})
接着login.vue里面需要加一下东西,箭头指向处
console.log(res.data.token)//在控制台查看输出的token
console.log('token对象',jwt_decode(res.data.token))//解析token
localStorage.setItem('mytoken',res.data.token)//本地存储
this.$router.push('/index');//登录成功后跳转到index.vue页面
vueproj里面router.js当然也要设置,都给复制过来了,代码上有注释
import Vue from 'vue'
import Router from 'vue-router'
import Index from './views/Index.vue'
import Login from './views/Login.vue'
import Register from './views/Register.vue'
import Not404 from './views/Not404.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
redirect:'/index'
},
{
path: '/index',
name: 'index',
component: Index
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/register',
name: 'register',
component: Register
}
]
})
//设置路由守卫
//设置路由守卫
router.beforeEach((to,from,next) => {
//除了login和register,其他的路由访问必须先登录
let tokenIsExists = localStorage.getItem('mytoken') ? true : false //检查本地存储中是否有token
if(to.path == '/login' || to.path == '/register'){
next() //允许访问路由
}else{
if(tokenIsExists){
next() //已经登录并取得token,允许访问路由
}else{
next('/login') //路由跳转到登录组件
}
}
})
export default router
接下来设置下http.js里面的内容,我都给粘贴进去了,里面有拦截token以及token过期的处理
import axios from 'axios'
import router from './router'
//设置axios,配置请求拦截器、响应拦截器
axios.interceptors.request.use(function (config) {
//当调用带鉴权的接口时,添加token头部标志
if(localStorage.getItem('mytoken')){
//在请求头部中加入token
config.headers.Authorization = localStorage.getItem('mytoken')
}
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
//当token过期时,获取错误信息,并清除本地存储的过期token
if(error.response.status == 401){
localStorage.removeItem('mytoken')
router.push('/login') //跳转到登录组件
}
return Promise.reject(error);
});
export default axios
index.vue里面需要修改添加的
<script>
export default{
data(){
return {
students:[],
currentUser:{}
}
},
//组件创建完成后执行的操作
created(){
this.$axios.get('http://localhost:3000/users')
.then(res => {
console.log( '查询结果:',res.data.data)
this.students = res.data.data
})
.catch(err => {
console.log('错误信息:' ,err)
})
}
}
</script>
最后测试一下
当本地存储没有的时候进入index首页,会直接跳转到login页面
登录成功后可以看到本地存储里面有我的token了,此时控制台里面也有我想要的数据
由于设置token的时限为10s,当过了10s后刷新就会再次进入login页面重新登录
上一篇: 无线局域网接入无线路由配置方法步骤