在前后端完全分离的情况下, vue 项目中实现 token 验证大致思路如下:
1, 第一次登录的时候, 前端调后端的登陆接口, 发送用户名和密码
2, 后端收到请求, 验证用户名和密码, 验证成功, 就给前端返回一个 token
3, 前端拿到 token, 将 token 存储到 localStorage 和 vuex 中, 并跳转路由页面
4, 前端每次跳转路由, 就判断 localStroage 中有无 token , 没有就跳转到登录页面, 有则跳转到对应路由页面
5, 每次调后端接口, 都要在请求头中加 token
6, 后端判断请求头中有无 token, 有 token, 就拿到 token 并验证 token, 验证成功就返回数据, 验证失败 (例如: token 过期) 就返回 401, 请求头中没有 token 也返回 401
7, 如果前端拿到状态码为 401, 就清除 token 信息并跳转到登录页面
vue-cli 搭建一个项目, 简单说明前端要做的事:
一, 调登录接口成功, 在回调函数中将 token 存储到 localStorage 和 vuex 中
login.vue
<template> <div> <input type="text" v-model="loginForm.username" placeholder="用户名"/> <input type="text" v-model="loginForm.password" placeholder="密码"/> <button @click="login">登录</button> </div></template> <script>import { mapMutations } from 'vuex';export default { data () { return { loginForm: { username: '', password:'' } }; }, methods: { ...mapMutations(['changeLogin']), login () { let _this = this; if (this.loginForm.username === ''|| this.loginForm.password ==='') { alert('账号或密码不能为空'); } else { this.axios({ method: 'post', url: '/user/login', data: _this.loginForm }).then(res => { console.log(res.data); _this.userToken = 'Bearer' + res.data.data.body.token; // 将用户 token 保存到 vuex 中 _this.changeLogin({ Authorization: _this.userToken }); _this.$router.push('/home'); alert('登陆成功'); }).catch(error => { alert('账号或密码错误'); console.log(error); }); } } }};</script>
store 文件夹下的 index.JS
import Vue from 'vue';import Vuex from 'vuex';Vue.use(Vuex); const store = new Vuex.Store({ state: { // 存储 token Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : ''}, mutations: { // 修改 token, 并将 token 存入 localStorage changeLogin (state, user) { state.Authorization = user.Authorization; localStorage.setItem('Authorization', user.Authorization); } }}); export default store;
二, 路由导航守卫
router 文件夹下的 index.JS
import Vue from 'vue';import Router from 'vue-router';import login from '@/components/login';import home from '@/components/home'; Vue.use(Router); const router = new Router({ routes: [ { path: '/', redirect: '/login' }, { path: '/login', name: 'login', component: login }, { path: '/home', name: 'home', component: home } ]}); // 导航守卫 // 使用 router.beforeEach 注册一个全局前置守卫, 判断用户是否登陆 router.beforeEach((to, from, next) => { if (to.path === '/login') { next(); } else { let token = localStorage.getItem('Authorization'); if (token === 'null' || token === '') { next('/login'); } else { next(); } }}); export default router;
三, 请求头加 token
// 添加请求拦截器, 在请求头中加 tokenaxios.interceptors.request.use( config => { if (localStorage.getItem('Authorization')) { config.headers.Authorization = localStorage.getItem('Authorization'); } return config; }, error => { return Promise.reject(error); });
四, 如果前端拿到状态码为 401, 就清除 token 信息并跳转到登录页面
localStorage.removeItem('Authorization'); this.$router.push('/login');
来源: http://www.jianshu.com/p/5a373acb5d44