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. 用js判断屏幕的宽度,改变html字体大小用rem布局

    if (document.documentElement.clientWidth > 600) {//页面宽度大于600px让其宽度等于600px,字体大小等于60px,居中 document. ...

  2. uoj#386. 【UNR #3】鸽子固定器(乱搞)

    传送门 题解 //minamoto #include<bits/stdc++.h> #define R register #define ll long long #define fp(i ...

  3. webpack 打包和手动创建一个vue的项目

    首先我们为啥要用webpack,为啥不用其他的打包的工具. 先听我捋捋, Webpack有人也称之为 模块打包机 ,由此也可以看出Webpack更侧重于模块打包,当然我们可以把开发中的所有资源(图片. ...

  4. jQuery EasyUI/TopJUI输入框事件监听

    jQuery EasyUI/TopJUI输入框事件监听 代码如下: <div data-toggle="topjui-panel" title="" da ...

  5. ES6入门教程---解构赋值和字符串扩展

    解构赋值: ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 数组的解构赋值: 按照对应的顺序解构. var arr = [1,[2,3]]; ...

  6. bzoj4650: [Noi2016]优秀的拆分 hash

    好气啊,没开longlong又biubiu了 底层: 用hash或者奇奇怪怪的算法兹磁logn求最长公共前后缀 思路: 统计出从一个点开始和结束的形如AA的子串的个数 统计的时候把相邻的结果相乘加起来 ...

  7. beanshell解析json(从简单到复杂)

    使用beanshell 解析单层Json: Json 数据如下: { "status":200, "code": 0, "message": ...

  8. 【手撸一个ORM】第五步、Expression(表达式目录树)转换为Where子句

    说明 在SQL中,查询.修改比较常用到WHERE子句,在这里根据使用场景不同,定义了两个类,一个用于查询,一个用于修改(插入)操作.原因是: 查询操作支持一级导航属性查询,如student.Schoo ...

  9. k8s的nfs存储外挂设置过程

    需求: 在k8s集群里的某个模块生成的目录文件或者更新的目录文件,存储到外面某台服务器上 1.安装nfs服务(192.168.1.2  Ubuntu 16.04) apt-get install nf ...

  10. C# 序列化与反序列化json

    与合作伙伴讨论问题,说到的c++与c#数据的转换调用,正好就说到了序列化与反序列化,同样也可用于不同语言间的调用,做了基础示例,作以下整理: using System.Data; using Syst ...