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认证的更多相关文章

  1. Vue 登录/登出以及JWT认证

    1. 后端代码概览 server/router/index.js 请求 router.get('/getUserInfo', function (req, res, next) { // 登录请求 r ...

  2. Vue登录登出以及JWT认证

    数据模型 主要用户名,密码,邮箱,头像,身份 const mongoose = require('mongoose') const schema = new mongoose.Schema({ use ...

  3. ThinkPHP---案例1登录登出和添加部门

    配置文件分3类:系统配置文件,分组配置文件,应用配置文件 ①系统配置文件ThinkPHP/Conf/convention.php: ②分组 / 模块 /平台配置文件Home/Conf/config.p ...

  4. flask 实现登录 登出 检查登录状态 的两种方法的总结

    这里我是根据两个项目的实际情况做的总结,方法一(来自项目一)的登录用的是用户名(字符串)和密码,前后端不分离,用form表单传递数据:方法二用的是手机号和密码登录,前后端分离,以json格式传递数据, ...

  5. Django项目: 4.用户登录登出功能

    用户登录登出功能 一.功能需求分析 1. 登录退出功能分析 流程图 功能 登录页面 登录功能 退出功能 二.登录页面 1. 接口设计 接口说明 类目 说明 请求方法 GET url定义 /user/l ...

  6. SpringBoot登录登出切面开发

    阅读本文约“2.5分钟” 本文开发环境是SpringBoot2.X版本. 对于系统而言(这里多指管理系统或部分具备登录登出功能的系统),登录登出是一个类权限验证的过程,现在一般是以token进行校验, ...

  7. Struts2学习第六课 实现登录登出功能

    关于Struts2请求的扩展名问题: 1).org.apache.struts2包下的default.properties中配置了struts2应用的一些常量 2).struts.action.ext ...

  8. ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 登录登出 上一章节我们总算完善了注册的功能,而且也添加了一个用户,现 ...

  9. jquery ajax常用的登录登出

    整理jquery+ajax的登录登出方法. //登录 var currentUserId = -1; $(function() { var timestamp = (new Date()).value ...

随机推荐

  1. [poj] Dungeon Master bfs

    Description You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is co ...

  2. cf808E(三分)

    题目链接:http://codeforces.com/problemset/problem/808/E 题意:给出n个体积为wi, 价值为ci的物品,背包容量为m,求能容纳的最大物品价值,其中 1&l ...

  3. Spring包的依赖关系以及提供下载

    https://www.jianshu.com/p/5b0c96975164 这篇简书叙述的很完整 一下是个人整和的炸包,里面有很全面的Spring包, 还有一些其他包,都是官网下载 emmmm... ...

  4. Python-10-条件和条件语句

    num = int(input('Enter a number: ')) if num > 0:     print('The number is positive') elif num < ...

  5. 不可见类有抽象父类,spring配置子类bean,注入父类,aop就可以切父类的方法

    public class TestBeanChild { int b = 1; public TestBean createDefault() { return new TestBeanDefault ...

  6. java--时间日期用法

    转载大神 https://www.cnblogs.com/Mr-Lyu/p/5736152.html https://blog.csdn.net/yf198708/article/details/51 ...

  7. .NET Core使用NLog通过Kafka实现日志收集

    微服务日志之.NET Core使用NLog通过Kafka实现日志收集 https://www.cnblogs.com/maxzhang1985/p/9522017.html 一.前言 NET Core ...

  8. 四则运算二(java web)

    最近我和我的小伙伴yaoyali结成对子,共同写网页版的四则运算.虽然现在还没弄好,但是比起上次用纯java写的四则运算有了很大改进. 一.存放四则运算题目和答案的类 package com.jaov ...

  9. 简单记录下SpringCloud的微服务架构和一些概念

    一.微服务的注册与发现——Eureka 和许多分布式设计一样,分布式的应用一般都会有一个服务中心,用于记录各个机器的信息.微服务架构也一样,我们把一个大的应用解耦成这么多个那么多个服务,那么在想要调用 ...

  10. Dell服务器安装系统中遇到的坑

    在本学期开学初期,由于后续实验的需要,老师为我们配置了服务器,该服务器的型号为Dell Power R730. 由于我也是一个小白,在服务器安装系统的过程中,遇到了一些麻烦,在这里记录下来,希望自己能 ...