|
|
/**
|
|
|
* 认证控制器
|
|
|
*
|
|
|
* 功能:处理用户注册、登录、获取信息等认证相关的业务逻辑
|
|
|
*
|
|
|
* 说明:Controller层处理业务逻辑,调用Model层操作数据库
|
|
|
*/
|
|
|
|
|
|
const User = require('../models/User');
|
|
|
const { hashPassword, comparePassword, generateToken } = require('../utils/encryption');
|
|
|
const {
|
|
|
validateRequired,
|
|
|
validateUsername,
|
|
|
validatePassword,
|
|
|
validateEmail,
|
|
|
validateBatch
|
|
|
} = require('../utils/validator');
|
|
|
const { success, error } = require('../utils/response');
|
|
|
const { BusinessError, ValidationError } = require('../middleware/errorHandler');
|
|
|
|
|
|
/**
|
|
|
* 用户注册
|
|
|
* POST /api/auth/register
|
|
|
*/
|
|
|
const register = async (req, res, next) => {
|
|
|
try {
|
|
|
const { username, password, real_name, phone, email, role } = req.body;
|
|
|
|
|
|
// 数据验证
|
|
|
const validation = validateBatch([
|
|
|
validateRequired(username, '用户名'),
|
|
|
validateRequired(password, '密码'),
|
|
|
validateUsername(username),
|
|
|
validatePassword(password)
|
|
|
]);
|
|
|
|
|
|
if (!validation.valid) {
|
|
|
throw new ValidationError('数据验证失败', validation.errors);
|
|
|
}
|
|
|
|
|
|
// 验证邮箱格式(如果提供了)
|
|
|
if (email && !validateEmail(email)) {
|
|
|
throw new ValidationError('邮箱格式不正确');
|
|
|
}
|
|
|
|
|
|
// 检查用户名是否已存在
|
|
|
const usernameExists = await User.isUsernameExists(username);
|
|
|
if (usernameExists) {
|
|
|
throw new BusinessError('用户名已被使用', 400);
|
|
|
}
|
|
|
|
|
|
// 检查邮箱是否已存在(如果提供了)
|
|
|
if (email) {
|
|
|
const emailExists = await User.isEmailExists(email);
|
|
|
if (emailExists) {
|
|
|
throw new BusinessError('邮箱已被使用', 400);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 加密密码
|
|
|
const hashedPassword = await hashPassword(password);
|
|
|
|
|
|
// 创建用户
|
|
|
const newUser = await User.create({
|
|
|
username,
|
|
|
password: hashedPassword,
|
|
|
real_name,
|
|
|
phone,
|
|
|
email,
|
|
|
role: role || 'customer' // 默认角色为顾客
|
|
|
});
|
|
|
|
|
|
// 生成token
|
|
|
const token = generateToken({
|
|
|
id: newUser.id,
|
|
|
username: newUser.username,
|
|
|
role: newUser.role
|
|
|
});
|
|
|
|
|
|
res.status(201).json(success({
|
|
|
user: newUser,
|
|
|
token
|
|
|
}, '注册成功'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 用户登录
|
|
|
* POST /api/auth/login
|
|
|
*/
|
|
|
const login = async (req, res, next) => {
|
|
|
try {
|
|
|
const { username, password } = req.body;
|
|
|
|
|
|
// 数据验证
|
|
|
const validation = validateBatch([
|
|
|
validateRequired(username, '用户名'),
|
|
|
validateRequired(password, '密码')
|
|
|
]);
|
|
|
|
|
|
if (!validation.valid) {
|
|
|
throw new ValidationError('数据验证失败', validation.errors);
|
|
|
}
|
|
|
|
|
|
// 查找用户
|
|
|
const user = await User.findByUsername(username);
|
|
|
if (!user) {
|
|
|
throw new BusinessError('用户名或密码错误', 401);
|
|
|
}
|
|
|
|
|
|
// 检查用户状态
|
|
|
if (user.status === 0) {
|
|
|
throw new BusinessError('账号已被禁用,请联系管理员', 403);
|
|
|
}
|
|
|
|
|
|
// 验证密码
|
|
|
const isPasswordValid = await comparePassword(password, user.password);
|
|
|
if (!isPasswordValid) {
|
|
|
throw new BusinessError('用户名或密码错误', 401);
|
|
|
}
|
|
|
|
|
|
// 生成token
|
|
|
const token = generateToken({
|
|
|
id: user.id,
|
|
|
username: user.username,
|
|
|
role: user.role
|
|
|
});
|
|
|
|
|
|
// 返回用户信息(不包含密码)
|
|
|
const userWithoutPassword = await User.findByIdWithoutPassword(user.id);
|
|
|
|
|
|
res.json(success({
|
|
|
user: userWithoutPassword,
|
|
|
token
|
|
|
}, '登录成功'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 获取当前登录用户信息
|
|
|
* GET /api/auth/profile
|
|
|
* 需要认证
|
|
|
*/
|
|
|
const getProfile = async (req, res, next) => {
|
|
|
try {
|
|
|
// req.user 由 authenticate 中间件设置
|
|
|
const user = await User.findByIdWithoutPassword(req.user.id);
|
|
|
|
|
|
if (!user) {
|
|
|
throw new BusinessError('用户不存在', 404);
|
|
|
}
|
|
|
|
|
|
res.json(success(user, '获取用户信息成功'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 更新当前用户信息
|
|
|
* PUT /api/auth/profile
|
|
|
* 需要认证
|
|
|
*/
|
|
|
const updateProfile = async (req, res, next) => {
|
|
|
try {
|
|
|
const { real_name, phone, email, avatar } = req.body;
|
|
|
|
|
|
// 验证邮箱格式(如果提供了)
|
|
|
if (email && !validateEmail(email)) {
|
|
|
throw new ValidationError('邮箱格式不正确');
|
|
|
}
|
|
|
|
|
|
// 检查邮箱是否被其他用户使用
|
|
|
if (email) {
|
|
|
const emailExists = await User.isEmailExists(email, req.user.id);
|
|
|
if (emailExists) {
|
|
|
throw new BusinessError('邮箱已被其他用户使用', 400);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 更新用户信息
|
|
|
const updatedUser = await User.update(req.user.id, {
|
|
|
real_name,
|
|
|
phone,
|
|
|
email,
|
|
|
avatar
|
|
|
});
|
|
|
|
|
|
res.json(success(updatedUser, '更新成功'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 修改密码
|
|
|
* PUT /api/auth/password
|
|
|
* 需要认证
|
|
|
*/
|
|
|
const changePassword = async (req, res, next) => {
|
|
|
try {
|
|
|
const { old_password, new_password } = req.body;
|
|
|
|
|
|
// 数据验证
|
|
|
const validation = validateBatch([
|
|
|
validateRequired(old_password, '旧密码'),
|
|
|
validateRequired(new_password, '新密码'),
|
|
|
validatePassword(new_password)
|
|
|
]);
|
|
|
|
|
|
if (!validation.valid) {
|
|
|
throw new ValidationError('数据验证失败', validation.errors);
|
|
|
}
|
|
|
|
|
|
// 检查新旧密码是否相同
|
|
|
if (old_password === new_password) {
|
|
|
throw new BusinessError('新密码不能与旧密码相同', 400);
|
|
|
}
|
|
|
|
|
|
// 获取用户信息
|
|
|
const user = await User.findById(req.user.id);
|
|
|
if (!user) {
|
|
|
throw new BusinessError('用户不存在', 404);
|
|
|
}
|
|
|
|
|
|
// 验证旧密码
|
|
|
const isPasswordValid = await comparePassword(old_password, user.password);
|
|
|
if (!isPasswordValid) {
|
|
|
throw new BusinessError('旧密码错误', 400);
|
|
|
}
|
|
|
|
|
|
// 加密新密码
|
|
|
const hashedPassword = await hashPassword(new_password);
|
|
|
|
|
|
// 更新密码
|
|
|
await User.updatePassword(req.user.id, hashedPassword);
|
|
|
|
|
|
res.json(success(null, '密码修改成功,请重新登录'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 获取用户列表(仅管理员)
|
|
|
* GET /api/auth/users
|
|
|
* 需要认证 + 管理员权限
|
|
|
*/
|
|
|
const getUserList = async (req, res, next) => {
|
|
|
try {
|
|
|
const { page = 1, pageSize = 10, role, status } = req.query;
|
|
|
|
|
|
const result = await User.findAll({
|
|
|
page: parseInt(page),
|
|
|
pageSize: parseInt(pageSize),
|
|
|
role,
|
|
|
status: status !== undefined ? parseInt(status) : undefined
|
|
|
});
|
|
|
|
|
|
res.json(success({
|
|
|
list: result.list,
|
|
|
pagination: {
|
|
|
total: result.total,
|
|
|
page: result.page,
|
|
|
pageSize: result.pageSize,
|
|
|
totalPages: Math.ceil(result.total / result.pageSize)
|
|
|
}
|
|
|
}, '获取用户列表成功'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 更新用户状态(仅管理员)
|
|
|
* PUT /api/auth/users/:id/status
|
|
|
* 需要认证 + 管理员权限
|
|
|
*/
|
|
|
const updateUserStatus = async (req, res, next) => {
|
|
|
try {
|
|
|
const { id } = req.params;
|
|
|
const { status } = req.body;
|
|
|
|
|
|
// 验证status值
|
|
|
if (status !== 0 && status !== 1) {
|
|
|
throw new ValidationError('状态值必须为0或1');
|
|
|
}
|
|
|
|
|
|
// 不能禁用自己
|
|
|
if (parseInt(id) === req.user.id) {
|
|
|
throw new BusinessError('不能禁用自己的账号', 400);
|
|
|
}
|
|
|
|
|
|
// 检查用户是否存在
|
|
|
const user = await User.findById(id);
|
|
|
if (!user) {
|
|
|
throw new BusinessError('用户不存在', 404);
|
|
|
}
|
|
|
|
|
|
// 更新状态
|
|
|
await User.updateStatus(id, status);
|
|
|
|
|
|
res.json(success(null, status === 1 ? '用户已启用' : '用户已禁用'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 删除用户(仅管理员)
|
|
|
* DELETE /api/auth/users/:id
|
|
|
* 需要认证 + 管理员权限
|
|
|
*/
|
|
|
const deleteUser = async (req, res, next) => {
|
|
|
try {
|
|
|
const { id } = req.params;
|
|
|
|
|
|
// 不能删除自己
|
|
|
if (parseInt(id) === req.user.id) {
|
|
|
throw new BusinessError('不能删除自己的账号', 400);
|
|
|
}
|
|
|
|
|
|
// 检查用户是否存在
|
|
|
const user = await User.findById(id);
|
|
|
if (!user) {
|
|
|
throw new BusinessError('用户不存在', 404);
|
|
|
}
|
|
|
|
|
|
// 删除用户
|
|
|
await User.delete(id);
|
|
|
|
|
|
res.json(success(null, '用户已删除'));
|
|
|
} catch (err) {
|
|
|
next(err);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 导出所有控制器函数
|
|
|
module.exports = {
|
|
|
register,
|
|
|
login,
|
|
|
getProfile,
|
|
|
updateProfile,
|
|
|
changePassword,
|
|
|
getUserList,
|
|
|
updateUserStatus,
|
|
|
deleteUser
|
|
|
};
|