使用JSON Web令牌验证Node.js API

282 阅读1分钟
原文链接: zhuanlan.zhihu.com

推荐先阅读:

Jothy:Server端的认证神器——JWT(一)zhuanlan.zhihu.com图标JSON Web Token 入门教程www.ruanyifeng.com图标


node实现简易的jwt认证


目录结构:



// user.js

const mongoose = require('mongoose')
const {Schema} = mongoose


const userSchema = new Schema({
	name: String,
	password: String,
	admin: Boolean
})

module.exports = mongoose.model('User', userSchema)


// config.js

module.exports = {
	'secret': 'ilovescotchyscotch', // 密钥
	'db': 'mongodb://localhost:/test'
}


// package.json

{
  "name": "token-jwt",
  "version": "1.0.0",
  "description": "node jwt",
  "main": "server.js",
  "scripts": {
    "start": "nodemon server.js"
  },
  "keywords": [
    "jwt"
  ],
  "author": "xyz",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4",
    "jsonwebtoken": "^8.4.0",
    "mongoose": "^5.3.13",
    "morgan": "^1.9.1"
  },
  "devDependencies": {
    "nodemon": "^1.18.6"
  }
}


// server.js

const Express = require('express')
const mongoose = require('mongoose')
const logger = require('morgan')
const jwt = require('jsonwebtoken')
const config = require('./config.js')
const User = require('./app/models/user.js')
const app = Express()
const PORT = process.env.PORT || 3000
const apiRoutes = Express.Router()

mongoose.connect(config.db, { useNewUrlParser: true })
app.set('superSecret', config.secret) // 设置secret
app.use(logger('dev'))
app.use(Express.json())
app.use(Express.urlencoded({ extended: false }))

app.get('/', function (req, res) {
	res.send(`api地址: localhost:3000/api`)
})

// 创建用户
app.post('/register', function (req, res) {
	console.log(req.body)
	const { name = '', password = '', admin = false} = req.body
	const requiredField = {
		name,
		password
	}
	let isPass = true
	for (let key in requiredField) {
		if (requiredField[key] === '' && isPass) {
			isPass = false
			res.json({
				msg: `${key}不能为空`
			})
		}
	}
	if (!isPass) { return }
	User.findOne({name}, function (err, user) {
		if (err) {
			res.send(err)
			return	
		}
		if (!user) {
			const user = new User({
				name,
				password, // 实际项目不会存明文
				admin
			})
			user.save(function (err, user) {
				if (err) {
					res.send(err)
				}
				res.json({
					msg: '创建成功'
				})
			})				
		} else {
			res.json({
				msg: '已存在同名用户'
			})			
		}
	})
})

// 生成token
app.get('/login', function (req, res) {
	console.log(req.query)
	const { name = '', password = ''} = req.query
	const requiredField = {
		name,
		password
	}
	let isPass = true
	for (let key in requiredField) {
		if (requiredField[key] === '' && isPass) {
			isPass = false
			res.json({
				msg: `${key}不能为空`
			})
		}
	}
	if (!isPass) { return }
	User.findOne({name, password}, function (err, user) {
		if (err) {
			res.send(err)
			return
		}
		if (!user) {
			res.json({
				msg: '用户名或者密码错误'
			})
		} else {
			const payload = {
				admin: user.admin
			}
			const token = jwt.sign(payload, app.get('superSecret'), {
				expiresIn: 1440
			})
			res.json({
				success: true,
				data: user,
				token
			})			
		}
	})
})

// token校验中间件
apiRoutes.use(function (req, res, next) {
	const token = req.body.token || req.query.token || req.headers['x-access-token']
	if (token) {
		jwt.verify(token, app.get('superSecret'), function (err, decoded) {
			if (err) {
				return res.json({ success: false, message: 'Failed to authenticate token.' })
			} else {
				req.decoded = decoded
				next()
			}
		})
	} else {
		return res.status(403).send({
			success: false,
			msg: '需要token令牌'
		})
	}
})

apiRoutes.get('/users', function (req, res) {
	User.find({}, function (err, users) {
		if (err) {
			res.send(err)
		}
		res.json({
			data: users
		})
	})
})

apiRoutes.get('/', function (req, res) {
	res.json({
		msg: '这里面的路由需要token验证。'
	})
})

app.use('/api', apiRoutes)

app.listen(PORT)
console.log(`server is on the port: ${PORT}`)


使用postman测试所有接口。