|
|
/**
|
|
|
* 加密和JWT工具
|
|
|
*
|
|
|
* 功能:
|
|
|
* 1. 密码加密和验证(使用bcrypt)
|
|
|
* 2. JWT token的生成和验证
|
|
|
*/
|
|
|
|
|
|
const bcrypt = require('bcryptjs');
|
|
|
const jwt = require('jsonwebtoken');
|
|
|
require('dotenv').config();
|
|
|
|
|
|
/**
|
|
|
* 密码加密
|
|
|
* @param {string} password - 原始密码
|
|
|
* @returns {Promise<string>} 加密后的密码
|
|
|
*
|
|
|
* 说明:bcrypt会自动加"盐",同一个密码每次加密结果都不同,但都能正确验证
|
|
|
*/
|
|
|
const hashPassword = async (password) => {
|
|
|
try {
|
|
|
// 生成盐(salt),10是加密强度,数字越大越安全但越慢
|
|
|
const salt = await bcrypt.genSalt(10);
|
|
|
// 使用盐加密密码
|
|
|
const hashedPassword = await bcrypt.hash(password, salt);
|
|
|
return hashedPassword;
|
|
|
} catch (error) {
|
|
|
throw new Error('密码加密失败: ' + error.message);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 密码验证
|
|
|
* @param {string} password - 用户输入的密码
|
|
|
* @param {string} hashedPassword - 数据库中存储的加密密码
|
|
|
* @returns {Promise<boolean>} 密码是否正确
|
|
|
*/
|
|
|
const comparePassword = async (password, hashedPassword) => {
|
|
|
try {
|
|
|
// bcrypt.compare会自动处理盐的比对
|
|
|
const isMatch = await bcrypt.compare(password, hashedPassword);
|
|
|
return isMatch;
|
|
|
} catch (error) {
|
|
|
throw new Error('密码验证失败: ' + error.message);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 生成JWT token
|
|
|
* @param {object} payload - 要存储在token中的数据(通常是用户ID和角色)
|
|
|
* @param {string} expiresIn - token过期时间(如 '24h', '7d')
|
|
|
* @returns {string} JWT token字符串
|
|
|
*
|
|
|
* 说明:JWT token就像一个电子身份证,包含用户信息,服务器可以验证真伪
|
|
|
*/
|
|
|
const generateToken = (payload, expiresIn = process.env.JWT_EXPIRES_IN || '24h') => {
|
|
|
try {
|
|
|
// 从环境变量获取密钥
|
|
|
const secret = process.env.JWT_SECRET;
|
|
|
|
|
|
if (!secret) {
|
|
|
throw new Error('JWT_SECRET 未配置');
|
|
|
}
|
|
|
|
|
|
// 签名生成token
|
|
|
const token = jwt.sign(payload, secret, { expiresIn });
|
|
|
return token;
|
|
|
} catch (error) {
|
|
|
throw new Error('Token生成失败: ' + error.message);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 验证JWT token
|
|
|
* @param {string} token - 要验证的token
|
|
|
* @returns {object} 解密后的数据
|
|
|
*
|
|
|
* 说明:验证token是否有效、是否过期、是否被篡改
|
|
|
*/
|
|
|
const verifyToken = (token) => {
|
|
|
try {
|
|
|
const secret = process.env.JWT_SECRET;
|
|
|
|
|
|
if (!secret) {
|
|
|
throw new Error('JWT_SECRET 未配置');
|
|
|
}
|
|
|
|
|
|
// 验证并解密token
|
|
|
const decoded = jwt.verify(token, secret);
|
|
|
return decoded;
|
|
|
} catch (error) {
|
|
|
if (error.name === 'TokenExpiredError') {
|
|
|
throw new Error('Token已过期,请重新登录');
|
|
|
} else if (error.name === 'JsonWebTokenError') {
|
|
|
throw new Error('无效的Token');
|
|
|
} else {
|
|
|
throw new Error('Token验证失败: ' + error.message);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 导出所有函数
|
|
|
module.exports = {
|
|
|
hashPassword,
|
|
|
comparePassword,
|
|
|
generateToken,
|
|
|
verifyToken
|
|
|
};
|