前后端交互实现的token登录请求-爱代码爱编程
目录
Token验证的基本流程
1.服务端收到请求,去验证用户名与密码
2.验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
3.客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
4.客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
5.服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
1.安装两个依赖包
npm install jsonwebtoken --save
npm install express-jwt@6.1.1
2.1 Token Express后端相关代码
定义生成token和获取token的函数
/token/token.js
const jwt = require('jsonwebtoken');
// 密钥
const jwtSecret = 'wanxianshan'; //签名
//登录接口 生成token的方法
// setToken携带的参数及参数的数量自定义
const setToken = function (uname) {
return new Promise((resolve, reject) => {
//expiresln 设置token过期的时间
//{ user_name: user_name, user_id: user_id } 传入需要解析的值( 一般为用户名,用户id 等)
// const token = jwt.sign({ user_name: user_name }, jwtSecret, { expiresIn: '24h' });
const token = jwt.sign({ uname: uname }, jwtSecret, { expiresIn: '24h' });
// 注意:expiresIn 过期事件,可以调整为24h后过期,10s太短了
resolve(token)
})
}
//各个接口需要验证token的方法
const getToken = function (token) {
return new Promise((resolve, reject) => {
// 'Bearer hasdghuwhiuwehdfhe.ashdfkhaewfhweiufhweuiof.sldhfjhfjkwhf'
if (!token) {
console.log('token是空的')
reject({
error: 'token 是空的'
})
}else {
// 验证token
var info = jwt.verify(token.split(' ')[1], jwtSecret);
resolve(info); //解析返回的值(sign 传入的值)
}
})
}
module.exports = {
setToken,
getToken
}
2.2解析token,验证token
/app.js
const express = require("express")
const app = express()
//express跨域
const cors = require("cors")
// 生成token和验证token是否正确的函数
const vertoken=require('./token/token')
//验证token是否过期,并规定哪些路由不用验证token
const expressJwt=require('express-jwt')
// 引入
const bookRouter = require("./router/bookRouter")
const userRouter = require("./router/userRouter")
// 使用cors
app.use(cors())
//=============================================验证token
//解析token获取用户信息
app.use(function(req, res, next) {
let token = req.headers['authorization'];
if(token == undefined){
next();
}else{
vertoken.getToken(token).then((data)=> {
console.log('解析后的token',data);
req.data = data;
next();
}).catch((error)=>{
next();
})
}
});
//验证token是否过期并规定那些路由不需要验证
app.use(expressJwt({
secret:'dkfjdjfkdfdfd',
// 加密算法
algorithms:['HS256']
}).unless({
path:['/login'] //不需要验证的接口名称
}))
/*
注意:直接安装使用expressJwt的时候,会在运行的时候报错
因为express-jwt升级了,后以前的用法应该是不同了
只需要将pakage.json中的express-jwt版本改为6.1.1,重新npm i 即可使用。
*/
//token失效返回信息
app.use(function(err,req,res,next){
if(err.status==401){
res.status(401).send('token失效11111111')
}else{
next()
}
})
// 使用路由
app.use(bookRouter)
app.use(userRouter)
app.listen(5000, () => {
console.log("服务器已开启在5000端口");
})
2.3登录接口
/router/usersRouter.js
let express = require('express');
let userRouter = express.Router();
let db = require('../service/db')
let vartoken = require('../utils/token');
userRouter.post('/login',(req,res)=>{
// 1. 用户名和密码
let {name,pwd} = req.body;
// 2. 链接数据库,查询当前信息是否正确
let sql = `select * from login where name='${name}' and pwd='${pwd}'`;
db.base(sql,null,(result)=>{
if(result.length > 0){
// 4. 使用用户名生成token,将token进行返回
// 生成token
vartoken.setToken(name).then(token=>{
data={
code:200,
msg:'登录成功',
token:token
}
res.send(data);
})
}else{
// 3. 不正确,返回登录失败
data={
code:201,
msg:'登录失败'
}
res.send(data);
}
})
})
// 导出
module.exports = userRouter;
3.token Vue前端相关代码
3.1axios的基础配置
/api/config.js
// axios的基础配置
import axios from 'axios'
// 1. 配置基础的请求路径【后端解决的跨域】
axios.defaults.baseURL = 'http://127.0.0.1:5000';
// 2. 模拟token
// localStorage.setItem('token','agsudiqye98qwhdawhdiashdioahiophdias');
// 3. axios 请求拦截器【token】
axios.interceptors.request.use(function (config) {
// 放入token信息
let token = localStorage.getItem('token'); // jwt-密钥,加密的内容-id-过期时间
if(token){
config.headers.Authorization = "Bearer "+token;
}
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 4. axios请求拦截器【拦截错误信息】
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
if(response.data.state == 401){
localStroage.clear();
window.location.reload();
}
return response
}, function (error) {
console.log('error',error.status)
// 对响应错误做点什么
return Promise.reject(error);
});
// 5.导出的接口
export default axios;
3.2获取后端接口
/api/request
import axios from './config'
// 登录
export function userLogin(data){
return axios({
url:'/login',
method:'post',
data
})
}
登录获取Token
/login.index
<template>
<div class="login">
<form-item label="用户名" prop="name">
<input
type="text"
v-model="ruleForm.name"
autocomplete="off"
></input>
</form-item>
<form-item label="密码" prop="pwd">
<input
type="password"
v-model="ruleForm.pwd"
autocomplete="off"
></input>
</form-item>
<form-item>
<button type="primary" @click="submitForm('ruleForm')"
>提交</button>
<button @click="resetForm('ruleForm')">重置</button>
</form-item>
</div>
</template>
<script>
import {userLogin} from "@/api/request"
export default {
data() {
// validatename validatePwd 都是自定义的验证规则
var validatename = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入用户名"));
} else {
if(/^\w{3,6}$/.test(value)){
callback();
}else{
callback(new Error("请输入3-6位的数字、字母、下划线"));
}
}
};
var validatePwd = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if(/^\w{3,6}$/.test(value)){
callback();
}else{
callback(new Error("请输入3-6位的数字、字母、下划线"));
}
}
};
return {
ruleForm: {
name: "",
pwd: ""
},
rules: {
name: [
{ validator: validatename, trigger: 'blur' }
],
pwd: [
{ validator: validatePwd, trigger: 'blur' }
],
},
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate(async (valid) => {
if (valid) {
// 验证用户名和密码是否正确
let res = await userLogin(this.ruleForm);
let {code,token} = res.data;
if(code == 200){
localStorage.setItem('token',token);
this.$message({
message: '登录成功',
type: 'success'
});
this.$router.push('/page')
}else{
this.$message.error('登录失败');
this.$refs[formName].resetFields();
}
} else {
console.log("error submit!!");
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
};
</script>
登录验证
router/index
// 路由拦截器 - 全局前置守卫
router.beforeEach((to, from, next) => {
let token = localStorage.getItem("token");
if (token) {
next();
} else {
if (to.fullPath == "/login") {
next();
} else {
next("/login");
}
}
});
退出登录
<button@click="quit()">退出</button>
methods: {
quit(){
localStorage.removeItem('token')
this.$router.push('index')
},
},
在token失效时返回status:401,前端清除token 根据status状态码返回登录页面