Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
总结:JWT就是token,它是生成token,校验token的一种工具。常用于分布式站点的单点登录
1. 客户端使用用户名跟密码请求登录
2. 服务端收到请求,去验证用户名与密码
3. 验证成功后,服务端会签发一个Token,再把这个 Token 发送给客户端
4. 客户端收到Token 以后可以把它存储起来,比如放在 Cookie 里或者 localStorage 里
5. 客户端每次向服务端请求资源的时候需要带着服务端签发的Token
6. 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据,另外服务端要支持CORS(跨来资源共享)的策略。
接下来进入正题------------------------------------------------------------------------------------------------------↓
1.初始化一个项目
npm init -y //生成package.json文件
2.下载所需依赖,生成node_modules文件和package-lock.json
npm i express cors jsonwebtoken -S //保存到当前项目中
3.新建一个uitls文件夹,存放工具函数,在里面新建一个tokenUitls.js用来封装生成token和验证token的函数,在里面先引入JWT,然后再封装函数,并暴露出去
// 第一步:引入jwt
let jwt = require("jsonwebtoken");
// JWT的组成部分
// 1.Header(头) 作用:记录令牌类型、签名算法等 例如:{"alg":"HS256","type":"JWT"}
// 2.Payload(有效载荷) 作用:携带一些用户信息 例如{"userId":"1","username":"mingzi"}
// 3.Signature(签名) 作用:是对前两部分的签名,防止Token被篡改、确保安全性 例如 计算出来的签名,一个字符串
// 密钥---字符串
let privatekey = 'testjwt'; //自定义密钥
// 过期时间单位 s
// let time = 60*60;
// 第二步:封装生成token的函数
function createToken(obj,exTime){
// obj代表有效载荷 privatekey代表密钥 expires过期时间 s
let tempToken = jwt.sign(obj,privatekey,{expiresIn:exTime})
// 把生成的token return出去
return tempToken
}
// 校验token的方法
function verifyToken(token){
return new Promise((resolve,reject)=>{
jwt.verify(token,privatekey,(err,data)=>{
if(err){
reject(err)
}else{
resolve(data)
}
})
})
}
// 第三步:暴露出去
module.exports = {
createToken,
verifyToken
}
4.新建app.js搭建服务器
先写一个登录接口,如果验证用户名和密码没问题,就调用生成token的函数,发送给前台res.send({ massage:"登录成功",token})
let express = require("express");
let app = express();
// 第四步:引入封装的生成token的方法
let { createToken,verifyToken } = require("./utils/tokenUtils")
// 解决跨域
let cors = require("cors");
app.use(cors());
// 解析post请求
app.use(express.urlencoded({extended:false}))
app.use(express.json())
// 登录接口
app.post("/login",(req,res)=>{
if(req.body.username!='xiaohao' || req.body.password!='123456'){
res.send("用户名不匹配")
}else{
let token = createToken({username:req.body.username},1800)
console.log('token',token);
res.send({
message:"登录成功",
token
})
}
})
// 用中间件拦截请求
app.use((req,res,next)=>{
// 获取前端传递过来的token
// console.log(req.headers);
let token = req.headers["authorization"];
// 如果有token执行校验token操作
if(token){
verifyToken(token).then((rel => {
// console.log(rel); //{ username: 'xiaohao', iat: 1667830826, exp: 1667832626 } 校验成功返回用户名,iat 发布时间,exp 到期时间
if(rel.username){
// 校验成功--中间件放行
next();
}
}),err => {
res.send("token过期,请重新登录" + err)
})
}else{
// 如果没有token
res.send("授权失败请先登录")
}
})
// 获取信息的接口
app.get("/msg",(req,res)=>{
res.send("其他信息")
})
app.listen(3000,() => {
console.log("您的服务器以光速启动--->>>>>>");
})
5.前台发起ajax请求,先登录,调用接口生成token,并存储在localstorage中,后获取信息,把存储的token放在请求头中,调用接口后,执行验证token的函数,验证成功放行后面的接口。
Document