在现代Web开发中,用户认证是一个至关重要的环节。随着前后端分离架构的流行,传统的Session认证方式逐渐暴露出了一些局限性。而JWT(JSON Web Token)作为一种无状态的认证机制,凭借其简洁、安全和高效的特性,在现代Web应用中得到了广泛应用。本文将详细介绍Session与Token认证的对比、JWT的原理与生成/验证流程、使用bcrypt加密用户密码,并通过实战展示如何在Node.js中实现登录鉴权中间件。
Session认证是一种传统的认证方式,其基本原理是在用户登录成功后,服务器会在内存中(或数据库、缓存中)存储一份用户的登录信息(Session),然后将Session ID通过Cookie返回给客户端。每次客户端请求时,都会携带这个Session ID,服务器通过Session ID查找对应的Session数据,从而验证用户身份。
优点
缺点
Token认证是一种无状态的认证方式,其核心思想是在用户登录成功后,服务器生成一个Token(通常是JWT)并返回给客户端。客户端在每次请求时,都会携带这个Token,服务器通过解析和验证Token来验证用户身份。
优点
缺点
JWT(JSON Web Token)是一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。JWT由三部分组成:Header(头部)、Payload(负载)和Signature(签名)。
生成JWT
创建Header:指定令牌类型和签名算法。
{
"alg": "HS256",
"typ": "JWT"
}
创建Payload:包含用户信息和过期时间等。
{
"sub": "1234567890",
"name": "John Doe",
"exp": 1625347200
}
验证JWT
bcrypt是一种基于Blowfish算法的密码哈希函数,专为抵御暴力破解攻击设计。它使用随机生成的字符串和可调节的工作因子来确保密码的安全性。
安装bcrypt
首先,你需要在Node.js项目中安装bcrypt库:
npm install bcrypt
bcrypt加密密码
const bcrypt = require('bcrypt');
async function hashPassword(password) {
// 生成随机数据串
const salt = await bcrypt.genSalt(10);
// 加密密码
const hashedPassword = await bcrypt.hash(password, salt);
return hashedPassword;
}
// 使用示例
hashPassword('my_password').then(hashedPassword => {
console.log('Hashed Password:', hashedPassword);
});
验证密码
const bcrypt = require('bcrypt');
async function comparePasswords(inputPassword, hashedPassword) {
const isMatch = await bcrypt.compare(inputPassword, hashedPassword);
return isMatch;
}
// 使用示例
comparePasswords('my_password', hashedPassword).then(isMatch => {
console.log('Password Match:', isMatch);
});
首先,你需要在Node.js项目中安装express和jsonwebtoken库:
npm install express jsonwebtoken
在项目的配置文件中(如config.js)设置JWT密钥:
module.exports = {
jwtSecret: 'your_jwt_secret_key'
};
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const config = require('./config');
const app = express();
// 模拟用户数据库
const users = [];
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (!user) {
return res.status(401).send('用户或则密码错误');
}
const isMatch = await bcrypt.compare(password, user.hashedPassword);
if (!isMatch) {
return res.status(401).send('用户或则密码错误');
}
const token = jwt.sign({ username: user.username }, config.jwtSecret, { expiresIn: '1h' });
res.json({ token });
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
const jwt = require('jsonwebtoken');
const config = require('./config');
function authenticateJWT(req, res, next) {
const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
if (!token) {
return res.status(403).send('认证的token数据必须传递');
}
jwt.verify(token, config.jwtSecret, (err, decoded) => {
if (err) {
return res.status(401).send('token数据错误');
}
req.user = decoded;
next();
});
}
// 使用中间件
app.use('/protected', authenticateJWT, (req, res) => {
res.send('调用此接口的都是需要认证的接口');
});
登录接口测试:
curl -X POST http://localhost:3000/login -H "Content-Type: application/json" -d '{"username":"testuser","password":"testpassword"}'
响应示例:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3R1c2VyIiwiaWF0IjoxNjI1MzQ3MjAwLCJleHAiOjE2MjUzNTA4MDB9.8y3H_m16G010a-35fJ8K5I9wM80_y3r4b3_Qe4-z55A"
}
受保护接口测试:
curl -X GET http://localhost:3000/protected -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3R1c2VyIiwiaWF0IjoxNjI1MzQ3MjAwLCJleHAiOjE2MjUzNTA4MDB9.8y3H_m16G010a-35fJ8K5I9wM80_y3r4b3_Qe4-z55A"
响应示例:
This is a protected route
通过本文,我们详细介绍了Session与Token认证的对比、JWT的原理与生成/验证流程、使用bcrypt加密用户密码,并通过实战展示了如何在Node.js中实现登录鉴权中间件。希望这些内容能够帮助你更好地理解和应用用户认证与JWT技术。
关注我!! 持续为你带来Nodejs相关内容。