文章预览
前言
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
更多关于token的使用参考文章:https://github.com/auth0/node-jsonwebtoken
一、安装与配置
1.1、安装jsonwebtoken
npm install jsonwebtoken
1.2、封装生成以及校验的jwt的模块
//封装jwt
const jwt = require('jsonwebtoken') //npm install jsonwebtoken
const { promisify } = require('util')
exports.sign = promisify(jwt.sign) //生成token
exports.verify = promisify(jwt.verify) //校验token
exports.decode = promisify(jwt.decode)
1.3、配置密钥
密钥用于token的验签
密钥就是一个随机生成的字符串
可以用UUID来生成
/**
* 默认配置
*/
module.exports = {
jwtSecret: '962df434-d199-4667-86f0-315872038bcc'
}
二、使用JWT
2.1、controller
const { User } = require('../model') //mongoDB的数据
const jwt = require('../utils/jwt')
const { jwtSecret } = require('../config/config.default')
// 用户注册
exports.register = async (req, res, next) => {
try {
// 获取数据
console.log(req.body)
// 保存数据
const user = new User(req.body.user)
await user.save()
const result = user.toJSON()
delete result.password
// 发送响应
res.status(201).json({
result
})
} catch (error) {
next(error)
}
}
// 用户登录
exports.login = async (req, res, next) => {
try {
// 生成token
const user = req.user.toJSON()
const token = await jwt.sign({
userId: user._id
}, jwtSecret, {
expiresIn: 60 * 60 * 24 //过期时间,以秒为单位
})
delete user.password //去除密码的数据
res.status(200).json({
...user, //解构user
token
})
} catch (error) {
next(error)
}
}
// 获取当前用户
exports.getCurrentUser = async (req, res, next) => {
try {
res.status(200).json({
user: req.user
})
} catch (error) {
next(error)
}
}
2.2、router
2.2.1、user.js
const express =require("express")
const userCtrl = require("../controller/user")
const userValidator = require("../validator/user")
const auth = require('../middleware/auth')
const router = express.Router()
/**
* 用户模块
*/
// 用户登录
router.get('/users/login', userValidator.login, userCtrl.login)
// 用户注册
router.post('/users', userValidator.register, userCtrl.register)
// 获取当前登录用户
router.get('/user', auth, userCtrl.getCurrentUser)
module.exports = router
2.2.2、index.js
const express =require("express")
const router = express.Router()
//用户模块路由
router.use(require('./user'))
module.exports = router
2.3、主模块app.js
const express = require("express")
const morgan = require("morgan") // npm i morgan 安装日志
const cors = require("cors") //npm i cors 跨域设置
const router = require("./router/index")
const errorHandler = require("./middleware/error-handler")
require("./model") //数据库初始化
const app = express()
// 日志
app.use(morgan('dev'))
// 配置请求体
app.use(express.json())
// 跨域设置
app.use(cors())
const PORT = process.env.PORT || 3000
// 挂载路由
app.use('/api',router)
// 挂载统一处理服务端错误中间件
app.use(errorHandler())
app.listen(PORT,() => {
console.log(`Server is running at http://locahost:${PORT}`)
})
2.4、token校验中间件
const { verify } = require('../utils/jwt')
const { jwtSecret } = require('../config/config.default')
const { User } = require('../model')
module.exports = async (req, res, next) => {
// 获取token
let token = req.headers['authorization']
token = token ? token.split('token ')[1] : null
if(!token){
return res.status(401).end("没有token")
}
try {
const decodedToken = await verify(token, jwtSecret)
console.log("============="+decodedToken.userId)
// 挂载数据
req.user = await User.findById(decodedToken.userId)
next()
} catch (error) {
res.status(401).json({
error: error.message
})
}
}
三、测试
3.1、登录生成token
3.1、获取用户校验token
在请求头中带上token