Node.js JWT认证教程
1. 项目介绍
JSON Web Token (JWT) 是一种安全的跨域身份验证解决方案,在现代Web应用中广泛使用。本教程将详细讲解如何在Node.js中实现JWT认证。
2. 项目准备
2.1 初始化项目
# 创建项目目录
mkdir nodejs-jwt-auth
cd nodejs-jwt-auth
# 初始化项目
npm init -y
# 安装依赖
npm install express jsonwebtoken bcryptjs body-parser
2.2 项目依赖说明
express
: Web应用框架jsonwebtoken
: JWT生成与验证bcryptjs
: 密码加密body-parser
: 解析请求体
3. 项目结构
nodejs-jwt-auth/
│
├── config/
│ └── database.js
├── models/
│ └── user.js
├── middleware/
│ └── auth.js
├── routes/
│ └── auth.js
├── server.js
└── package.json
4. 详细实现
4.1 数据库配置 (config/database.js)
module.exports = {
secret: 'your_jwt_secret_key',
database: 'mongodb://localhost:27017/jwt-auth-demo'
};
4.2 用户模型 (models/user.js)
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
// 密码加密中间件
UserSchema.pre('save', function(next) {
if (!this.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(this.password, salt, (err, hash) => {
if (err) return next(err);
this.password = hash;
next();
});
});
});
// 密码验证方法
UserSchema.methods.comparePassword = function(candidatePassword) {
return bcrypt.compareSync(candidatePassword, this.password);
};
module.exports = mongoose.model('User', UserSchema);
4.3 认证中间件 (middleware/auth.js)
const jwt = require('jsonwebtoken');
const config = require('../config/database');
module.exports = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(403).json({
success: false,
message: '未提供认证Token'
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).json({
success: false,
message: 'Token无效'
});
}
req.userId = decoded.id;
next();
});
};
4.4 路由 (routes/auth.js)
const express = require('express');
const jwt = require('jsonwebtoken');
const router = express.Router();
const User = require('../models/user');
const config = require('../config/database');
const authMiddleware = require('../middleware/auth');
// 用户注册
router.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
const existingUser = await User.findOne({ username });
if (existingUser) {
return res.status(400).json({
success: false,
message: '用户已存在'
});
}
const user = new User({ username, password });
await user.save();
res.status(201).json({
success: true,
message: '注册成功'
});
} catch (error) {
res.status(500).json({
success: false,
message: '服务器错误'
});
}
});
// 用户登录
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({
success: false,
message: '用户不存在'
});
}
const isMatch = user.comparePassword(password);
if (!isMatch) {
return res.status(401).json({
success: false,
message: '密码错误'
});
}
const token = jwt.sign(
{ id: user._id },
config.secret,
{ expiresIn: '24h' }
);
res.json({
success: true,
token: `Bearer ${token}`
});
} catch (error) {
res.status(500).json({
success: false,
message: '服务器错误'
});
}
});
// 受保护的路由
router.get('/profile', authMiddleware, async (req, res) => {
try {
const user = await User.findById(req.userId).select('-password');
res.json({
success: true,
user
});
} catch (error) {
res.status(500).json({
success: false,
message: '服务器错误'
});
}
});
module.exports = router;
4.5 服务器入口 (server.js)
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const config = require('./config/database');
const authRoutes = require('./routes/auth');
const app = express();
// 数据库连接
mongoose.connect(config.database, {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 中间件
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 路由
app.use('/api/auth', authRoutes);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服务器运行在 ${PORT} 端口`);
});
5. 使用说明
5.1 注册用户
POST /api/auth/register
{
"username": "testuser",
"password": "123456"
}
5.2 用户登录
POST /api/auth/login
{
"username": "testuser",
"password": "123456"
}
5.3 访问受保护路由
GET /api/auth/profile
Authorization: Bearer <token>
6. 安全建议
- 使用HTTPS保护传输
- 定期更新JWT密钥
- 设置合理的Token过期时间
- 对敏感操作进行二次验证
7. 注意事项
- 生产环境中应使用环境变量管理密钥
- 建议使用更强的加密算法
- 根据实际需求调整Token过期策略