vue2和node.js中的token
技术:vue2+node.js
一、token
Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
二、token的流程
三、vue中的配置
1.获得token并存储在本地
ps:我使用的vuex来进行数据管理
a.页面
<script>
export default {
data(){
return{
// 用户名
username:'',
// 密码
password:''
}
},
methods:{
// 登录函数
async login(){
const {username,password} = this
try {
// 通过 store.dispatch 方法触发Action
await this.$store.dispatch('userLogin',{username,password} )
// this.$route.query.redirect:原本你想去的路由
let goPath = this.$route.query.redirect||'/home';
// 跳转到首页
this.$router.push(goPath);
alert("登录成功")
} catch (err) {
alert(err.message)
}
}
}
}
</script>
在form表单中填写用户名和密码后,调用store.dispatch 方法触发Action中的userLogin
b.vuex
(1).action中
//用户登录
async userLogin({commit}, data) {
// reqUserLogin是我封装的登录请求,data包含了username和password
let result = await reqUserLogin(data);
//登录成功
if (result.code == 0) {
// 存储token
commit('SET_TOKEN', result.data.token);
//获取token【持久化存储】,将token存入本地缓存
localStorage.setItem('TOKEN', result.data.token);
return 'ok';
} else {
//登录失败
return Promise.reject(new Error(result.message));
}
},
(2).state中
let state = {
// 获取本地存储的token,当token不存在时,取为空
token: localStorage.getItem("TOKEN") || '',
};
(3).mutations中
let mutations = {
SET_TOKEN(state, token) {
state.token = token
}
};
c.请求
index.js
//统一管理项目全部的接口
import requests from "./requests";
import qs from 'qs';
//登录的接口:请求体携带参数 username&&password
export const reqUserLogin = (data)=>requests({url:`/api/login`,method:'post',data:qs.stringify(data)});
2.请求携带token的配置
ps:这里我对axios二次封装了
requests.js
//对于axios进行二次封装
import axios from "axios";
//获取仓库:存储数据
import store from "@/store";
//axios.create方法执行,其实返回一个axios和request一样的
let requests = axios.create({
//超时的设置
timeout: 5000
});
//请求拦截器:将来项目中【N个请求】,只要发请求,会触发请求拦截器!!!
requests.interceptors.request.use(config => {
//请求拦截器:请求头【header】,请求头能给服务器携带参数
//请求拦截器:给服务器携带请求们的公共的参数
//token[公共参数]
if(store.state.user.token){
config.headers.Authorization = store.state.user.token;
}
return config;
});
//响应拦截器:请求数据返回会执行
requests.interceptors.response.use((res) => {
//res:实质就是项目中发请求、服务器返回的数据
return res.data;
}, (err) => {
//温馨提示:某一天发请求,请求失败,请求失败的信息打印出来
alert(err.message);
//终止Promise链
return new Promise();
});
//最后需要暴露:暴露的是添加新的功能的axios,即为requests
export default requests;
有了请求拦截器之后,后续的请求都可以自动携带state中的token了。
3.token过期的操作
如果token为空或者过期,后端会发相应的错误码,让你重新登录。
此时的步骤大致为:
1.清除本地的token
2.重新登录获取token
4.限制用户未登录时的路由跳转
有时候用户并没有登录,这时候个人信息等界面都不能进行路由跳转
这时候就需要路由守卫---主要用来通过跳转或取消的方式守卫导航
//全局守卫:只要项目中有任何路由变化,全局守卫都会进行拦截【符合条件走你,不符合条件不能访问】
//全局守卫:全局前置守卫【访问之前进行触发】
//全局前置守卫
router.beforeEach(async (to, from, next) => {
//to:去的那个路由的信息
//from:从那个路由而来的信息
//next:放行函数!!!!!!
//第一种:next(),放行函数,放行到它想去的路由!!!
//第二种:next(path),守卫指定放行到那个路由去?
//用户是否登录:取决于仓库里面是否有token!!!
//每一次路由跳转之前需要用有用户信息在跳转,没有发请求获取用户信息在跳转!!!!
//token
let hasToken = store.state.user.token;
//用户信息
let hasNickName = store.state.user.username;
//用户登录
if (hasToken) {
//用户登录了,不能去login
if (to.path == "/login") {
next('/home');
} else {
//用户登陆了,而且还有用户信息【去的并非是login】
if (hasNickName) {
next();
} else {
//用户登陆了,但是没有用户信息
try {
//发请求获取用户信息以后在放行
await store.dispatch('getUserInfo');
next();
} catch (error) {
//用户没有信息,还携带token发请求获取用户信息【失败】
//token【学生证失效了】
//token失效:本地清空数据、服务器的token通知服务器清除
await store.dispatch('logout');
//回到登录页,重新获取一个新的学生证
console.log("用户没有信息,token失效");
next('/login');
}
}
}
} else {
//用户未登录||目前的判断都是放行.将来这里会'回手掏'增加一些判断
//用户未登录:不能进入/trade、/pay、/paysuccess、/center、/center/myorder /center/teamorder
// let toPath = to.path;
// if (toPath.indexOf('trade') != -1 || toPath.indexOf('pay') != -1 || toPath.indexOf('center') != -1) {
// next('/login?redirect='+toPath);
// } else {
// next();
// }
next();
}
});
四、node.js中的配置
1.配置跨域
1.运行如下的命令,安装 cors
中间件:
npm i cors@2.8.5
2.在 app.js
中导入并配置 cors
中间件:
// 导入 cors 中间件
const cors = require('cors')
// 将 cors 注册为全局中间件
app.use(cors())
2.生成token
在生成 Token 字符串的时候,一定要剔除 密码的值!!!!!!!
1.通过 ES6 的高级语法,快速剔除 密码
的值:
// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = { ...results[0], password: '', user_pic: '' }
2.运行如下的命令,安装生成 Token 字符串的包:
npm i jsonwebtoken@8.5.1
3.在 /router_handler/user.js
模块的头部区域,导入 jsonwebtoken
包:
// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')
4.创建 config.js
文件,并向外共享 加密 和 还原 Token 的 jwtSecretKey
字符串:
module.exports = {
jwtSecretKey: 'itheima No1. ^_^',
}
5.将用户信息对象加密成 Token 字符串:
// 导入配置文件
const config = require('../config')
// 生成 Token 字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
expiresIn: '10h', // token 有效期为 10 个小时
})
6.将生成的 Token 字符串响应给客户端:
res.send({
status: 0,
message: '登录成功!',
// 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
token: 'Bearer ' + tokenStr,
})
3.解析token
1.运行如下的命令,安装解析 Token 的中间件:
npm i express-jwt@5.3.3
2.在 app.js
中注册路由之前,配置解析 Token 的中间件:
// 导入配置文件
const config = require('./config')
// 解析 token 的中间件
const expressJWT = require('express-jwt')
// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/api\//] }))
3.在 app.js
中的 错误级别中间件
里面,捕获并处理 Token 认证失败后的错误:
// 错误中间件
app.use(function (err, req, res, next) {
// 省略其它代码...
// 捕获身份认证失败的错误
if (err.name === 'UnauthorizedError') return res.cc('身份认证失败!')
// 未知错误...
})