利用Vue.js实现登录/登出以及JWT认证
JSON Web Token 入门教程:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
后端代码地址:https://github.com/lison16/vue-cource/commit/c0341e8ea79d876ae552281ad8c1f1da5049434f
代码结构:


uer.js:封装了登录和授权两个接口。
import axios from "./index";
export const getUserInfo = ({ userId }) => {
debugger;
return axios.request({
url: "/getUserInfo",
method: "post",
data: {
userId
}
});
};
export const login = ({ userName, password }) => {
return axios.request({
url: "/index/login",
method: "post",
data: {
userName,
password
}
});
};
export const authorization = () => {
return axios.request({
url: "/users/authorization",
method: "get"
});
};
/src/store/module/user.js:由于是异步操作,所以都放在了actions中。
import { login, authorization } from "@/api/user";
import { setToken } from "@/lib/util";
const state = {
//
userName: "Caoqi"
};
const getters = {
firstLetter: state => {
return state.userName.substr(0, 1);
}
};
const mutations = {
//
SET_USER_NAME(state, params) {
state.userName = params.userName;
}
};
const actions = {
login({ commit }, { userName, password }) {
return new Promise((resolve, reject) => {
login({ userName, password })
.then(res => {
debugger;
if (res.data.code === 200 && res.data.data.token) {
setToken(res.data.data.token);
resolve();
} else {
reject(new Error("错误"));
}
})
.catch(error => {
reject(error);
});
});
},
authorization({ commit }, token) {
return new Promise((resolve, reject) => {
authorization()
.then(res => {
if (parseInt(res.data.code) === 401) {
reject(new Error("token error"));
} else {
setToken(res.data.data.token);
resolve();
}
})
.catch(error => {
reject(error);
});
});
},
logout() {
setToken("");
}
};
export default {
//namespaced:true,//有利于模块更加密闭,不受外界的干扰
state,
getters,
mutations,
actions
};
/src/lib/axios.js:
import axios from "axios";
import { baseURL } from "@/config";
import { getToken } from '@/lib/util';
//ES6类的写法
class HttpRequest {
//ES6默认参数
constructor(baseUrl = baseURL) {
this.baseUrl = baseUrl;
this.queue = {}; //将请求都放到队列中
}
getInsideConfig() {
const config = {
baseURL: this.baseUrl,
hearders: {
//
}
};
return config;
}
//封装拦截器
interceptors(instance, url) {
instance.interceptors.request.use(
config => {
//添加全局的loading
//Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组
if (!Object.keys(this.queue).length) {
//spin.show
}
this.queue[url] = true;
config.headers['Authorization'] = getToken();
return config;
},
error => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
res => {
delete this.queue[url];
const { data, status } = res;
return { data, status };
},
error => {
delete this.queue[url];
return Promise.reject(error);
}
);
} request(options) {
const instance = axios.create();
/**
* Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
* const target = { a: 1, b: 2 };
* const source = { b: 4, c: 5 };
* const returnedTarget = Object.assign(target, source);
* console.log(target);
* expected output: Object { a: 1, b: 4, c: 5 }
*/
options = Object.assign(this.getInsideConfig(), options);
this.interceptors(instance, options.url);
return instance(options);
}
} export default HttpRequest;
login.vue:
<template>
<div>
<div>
<input v-model="userName">
</div>
<div>
<input type="password" v-model="password">
</div>
<div>
<button @click="handleSubmit">登录</button>
</div>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "login_page",
data() {
return {
userName: "",
password: ""
};
},
methods: {
...mapActions(["login"]),
handleSubmit() {
this.login({
userName: this.userName,
password: this.password
})
.then(() => {
console.log("success!!");
this.$router.push({
name: "home"
});
})
.catch(error => {
console.log(error);
});
}
}
};
</script>
/src/router/index.js:跳转到任何页面前都要验证token
import Vue from "vue";
import Router from "vue-router";
import routes from "./router";
import store from "@/store";
import { setTitle, setToken, getToken } from "@/lib/util"; Vue.use(Router); const router = new Router({
routes
}); const HAS_LOGINED = false;
//全局前置守卫
/*
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子
*/
//模拟登陆验证逻辑:当跳转页面为登陆页面且已经登陆时,直接跳转到home页面,如果跳转页面不为登录页且已经登陆,则继续执行,否则直接跳转到登录页
router.beforeEach((to, from, next) => {
to.meta && setTitle(to.meta.title);
debugger
const token = getToken();
if (token) {
store
.dispatch("authorization", token)
.then(() => {
if (to.name == "login") {
next({ name: "home" });
} else {
next();
}
})
.catch(() => {
setToken("");
next({ name: "login" });
});
} else {
if (to.name === "login") next();
else next({ name: "login" });
}
}); export default router;
src/views/Home.vue:包含登出效果:清除cookie,页面跳转到login.vue
<template>
<div class="home">
<b>{{ food }}</b>
<button @click="handleClick('back')">返回上一页</button>
<button @click="handleClick('push')">跳转到parent</button>
<button @click="handleClick('replace')">替换到parent</button>
<button @click="getInfo">请求数据</button>
<button @click="handleLogout">退出登录</button>
</div>
</template> <script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";
import { getUserInfo } from '@/api/user'
import { mapActions } from 'vuex'
export default {
name: "home",
components: {
HelloWorld
},
props: {
food: {
type: String,
default: "apple"
}
},
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
next(vm => {
//若想使用实例,可使用这种方法
console.log(vm);
});
},
beforeRouteLeave(to, from, next) {
// const leave = confirm('您确定要离开吗?')
// if (leave) next()
// else next(false)
next();
},
methods: {
...mapActions([
'logout'
]),
handleClick(type) {
if (type === "back") {
//this.$router.back();
this.$router.go(-1);
} else if (type === "push") {
const name = "caoqi";
//使用push会在浏览器中加入一个记录
//使用路径跳转
//this.$router.push("/parent");
//还可以使用命名路由的方式:
this.$router.push({
// name: "parent",
// //加入name参数,http://localhost:8080/#/parent?name=caoqi
// query: {
// name: 'caoqi'
// } // name: "argu",
// //加入name参数,http://localhost:8080/#/argu/caoqi
// params: {
// name: 'caoqi'
// } //ES6写法:
path: `/argu/${name}`
});
} else if (type === "replace") {
//使用replace不会在浏览历史中加入记录
this.$router.replace({
name: "parent"
});
}
},
getInfo() {
getUserInfo({ userId: 21 }).then(res => {
console.log("res: ", res);
});
},
handleLogout () {
this.logout()
this.$router.push({
name: 'login'
})
}
}
};
</script>
效果图:(一开始登录失败,因为后台设置了密码为123,登录成功后,如果在cookie有效的时间段内,登录系统其它页面则无需登录,若把cookie清除则再查看系统其它页面,则直接跳转到登录页进行登录操作)

利用Vue.js实现登录/登出以及JWT认证的更多相关文章
- Vue 登录/登出以及JWT认证
1. 后端代码概览 server/router/index.js 请求 router.get('/getUserInfo', function (req, res, next) { // 登录请求 r ...
- Vue登录登出以及JWT认证
数据模型 主要用户名,密码,邮箱,头像,身份 const mongoose = require('mongoose') const schema = new mongoose.Schema({ use ...
- ThinkPHP---案例1登录登出和添加部门
配置文件分3类:系统配置文件,分组配置文件,应用配置文件 ①系统配置文件ThinkPHP/Conf/convention.php: ②分组 / 模块 /平台配置文件Home/Conf/config.p ...
- flask 实现登录 登出 检查登录状态 的两种方法的总结
这里我是根据两个项目的实际情况做的总结,方法一(来自项目一)的登录用的是用户名(字符串)和密码,前后端不分离,用form表单传递数据:方法二用的是手机号和密码登录,前后端分离,以json格式传递数据, ...
- Django项目: 4.用户登录登出功能
用户登录登出功能 一.功能需求分析 1. 登录退出功能分析 流程图 功能 登录页面 登录功能 退出功能 二.登录页面 1. 接口设计 接口说明 类目 说明 请求方法 GET url定义 /user/l ...
- SpringBoot登录登出切面开发
阅读本文约“2.5分钟” 本文开发环境是SpringBoot2.X版本. 对于系统而言(这里多指管理系统或部分具备登录登出功能的系统),登录登出是一个类权限验证的过程,现在一般是以token进行校验, ...
- Struts2学习第六课 实现登录登出功能
关于Struts2请求的扩展名问题: 1).org.apache.struts2包下的default.properties中配置了struts2应用的一些常量 2).struts.action.ext ...
- ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 登录登出 上一章节我们总算完善了注册的功能,而且也添加了一个用户,现 ...
- jquery ajax常用的登录登出
整理jquery+ajax的登录登出方法. //登录 var currentUserId = -1; $(function() { var timestamp = (new Date()).value ...
随机推荐
- Ext.apply(src,apply) 和 Ext.applyIf(src,apply)比较(转)
Ext.onReady(function(){ /* * Ext.apply(src,apply) 和 Ext.applyIf(src,apply) 两个方法的使用和区别比较 */ //Ext.app ...
- ue4学习资料
官网中文 https://docs.unrealengine.com/latest/CHN/index.html 官网英文 https://docs.unrealengine.com/latest/I ...
- DOTween Sequence 使用图解
http://blog.csdn.net/jiejieup/article/details/41521577 最近在使用DOTween制作一些动画过渡的内容,发现非常好用,使用Sequence类可以方 ...
- LibreOJ #2036. 「SHOI2015」自动刷题机
#2036. 「SHOI2015」自动刷题机 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 曾经发明了信号增幅仪的发明家 SHTSC 又公开 ...
- 2、CreateJS介绍-TweenJS
需要在html5文件中引入的CreateJS库文件是easeljs-0.7.1.min.js和tweenjs-0.5.1.min.js HTML5文件如下: <!DOCTYPE html> ...
- JMeter(5) JMeter之BeanShell使用
BeanShell介绍 BeanShell是用Java写成的,一个小型的.免费的.可以下载的.嵌入式的Java源代码解释器,具有对象脚本语言特性.本篇只记录一下基本的使用.有以下五个组件: Beans ...
- 搞定vscode编写java
下载vscode: 地址: https://code.visualstudio.com/ 安装插件 我这里下载的是绿色版,所以解压后 向桌面发送一个快捷方式 找到VS Code 的快捷方式位置: 右键 ...
- Yii2.0权限系统,使用PhpManager的方式
网上搜了一大堆yii2.0权限系统,大抵都是千篇一律,而且基本上都是DbManager.看了半天官方文档之后,终于知道了PhpManager的方式下,是怎么引入权限系统.介绍下我自己的使用.首先,配置 ...
- 老男孩IT教育-每日一题汇总
老男孩IT教育-每日一题汇总 第几天 第几周 日期 快速访问链接 第123天 第二十五周 2017年8月25日 出现Swap file….already exists以下错误如何解决? 第122天 2 ...
- JSON.stringify 语法讲解
作用:这个函数的作用主要是为了系列化对象的. 可能有些人对系列化这个词过敏,我的理解很简单.就是说把原来是对象的类型转换成字符串类型(或者更确切的说是json类型的).就这么简单.打个比方说,你有一个 ...