Generating commit message...
This commit is contained in:
266
backend/src/controllers/authController.js
Normal file
266
backend/src/controllers/authController.js
Normal file
@@ -0,0 +1,266 @@
|
||||
const jwt = require('jsonwebtoken')
|
||||
const { User } = require('../models/User')
|
||||
const { AppError } = require('../utils/errors')
|
||||
const { success } = require('../utils/response')
|
||||
|
||||
// 生成JWT Token
|
||||
const generateToken = (userId) => {
|
||||
return jwt.sign(
|
||||
{ userId },
|
||||
process.env.JWT_SECRET || 'your-secret-key',
|
||||
{ expiresIn: process.env.JWT_EXPIRE || '7d' }
|
||||
)
|
||||
}
|
||||
|
||||
// 用户注册
|
||||
const register = async (req, res, next) => {
|
||||
try {
|
||||
const { username, password, nickname, email, phone } = req.body
|
||||
|
||||
// 检查用户名是否已存在
|
||||
const existingUser = await User.findOne({
|
||||
$or: [
|
||||
{ username },
|
||||
{ email: email || null },
|
||||
{ phone: phone || null }
|
||||
]
|
||||
})
|
||||
|
||||
if (existingUser) {
|
||||
if (existingUser.username === username) {
|
||||
throw new AppError('用户名已存在', 400)
|
||||
}
|
||||
if (existingUser.email === email) {
|
||||
throw new AppError('邮箱已存在', 400)
|
||||
}
|
||||
if (existingUser.phone === phone) {
|
||||
throw new AppError('手机号已存在', 400)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
const user = new User({
|
||||
username,
|
||||
password,
|
||||
nickname: nickname || username,
|
||||
email,
|
||||
phone
|
||||
})
|
||||
|
||||
await user.save()
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(user._id)
|
||||
|
||||
// 更新最后登录时间
|
||||
user.lastLoginAt = new Date()
|
||||
await user.save()
|
||||
|
||||
res.status(201).json(success({
|
||||
user: user.toJSON(),
|
||||
token,
|
||||
message: '注册成功'
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
const login = async (req, res, next) => {
|
||||
try {
|
||||
const { username, password } = req.body
|
||||
|
||||
if (!username || !password) {
|
||||
throw new AppError('用户名和密码不能为空', 400)
|
||||
}
|
||||
|
||||
// 查找用户(支持用户名、邮箱、手机号登录)
|
||||
const user = await User.findOne({
|
||||
$or: [
|
||||
{ username },
|
||||
{ email: username },
|
||||
{ phone: username }
|
||||
]
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404)
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (!user.isActive()) {
|
||||
throw new AppError('账户已被禁用', 403)
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
const isPasswordValid = await user.comparePassword(password)
|
||||
if (!isPasswordValid) {
|
||||
throw new AppError('密码错误', 401)
|
||||
}
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(user._id)
|
||||
|
||||
// 更新最后登录时间
|
||||
user.lastLoginAt = new Date()
|
||||
await user.save()
|
||||
|
||||
res.json(success({
|
||||
user: user.toJSON(),
|
||||
token,
|
||||
message: '登录成功'
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
const getCurrentUser = async (req, res, next) => {
|
||||
try {
|
||||
const user = await User.findById(req.userId)
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404)
|
||||
}
|
||||
|
||||
res.json(success({
|
||||
user: user.toJSON()
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
const updateProfile = async (req, res, next) => {
|
||||
try {
|
||||
const { nickname, avatar, gender, birthday } = req.body
|
||||
const updates = {}
|
||||
|
||||
if (nickname !== undefined) updates.nickname = nickname
|
||||
if (avatar !== undefined) updates.avatar = avatar
|
||||
if (gender !== undefined) updates.gender = gender
|
||||
if (birthday !== undefined) updates.birthday = birthday
|
||||
|
||||
const user = await User.findByIdAndUpdate(
|
||||
req.userId,
|
||||
updates,
|
||||
{ new: true, runValidators: true }
|
||||
)
|
||||
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404)
|
||||
}
|
||||
|
||||
res.json(success({
|
||||
user: user.toJSON(),
|
||||
message: '个人信息更新成功'
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
const changePassword = async (req, res, next) => {
|
||||
try {
|
||||
const { currentPassword, newPassword } = req.body
|
||||
|
||||
if (!currentPassword || !newPassword) {
|
||||
throw new AppError('当前密码和新密码不能为空', 400)
|
||||
}
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
throw new AppError('新密码长度不能少于6位', 400)
|
||||
}
|
||||
|
||||
const user = await User.findById(req.userId)
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404)
|
||||
}
|
||||
|
||||
// 验证当前密码
|
||||
const isCurrentPasswordValid = await user.comparePassword(currentPassword)
|
||||
if (!isCurrentPasswordValid) {
|
||||
throw new AppError('当前密码错误', 401)
|
||||
}
|
||||
|
||||
// 更新密码
|
||||
user.password = newPassword
|
||||
await user.save()
|
||||
|
||||
res.json(success({
|
||||
message: '密码修改成功'
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 微信登录/注册
|
||||
const wechatLogin = async (req, res, next) => {
|
||||
try {
|
||||
const { code, userInfo } = req.body
|
||||
|
||||
if (!code) {
|
||||
throw new AppError('微信授权码不能为空', 400)
|
||||
}
|
||||
|
||||
// 这里应该调用微信API获取openid和unionid
|
||||
// 模拟获取微信用户信息
|
||||
const wechatUserInfo = {
|
||||
openid: `mock_openid_${Date.now()}`,
|
||||
unionid: `mock_unionid_${Date.now()}`,
|
||||
nickname: userInfo?.nickName || '微信用户',
|
||||
avatar: userInfo?.avatarUrl || '',
|
||||
gender: userInfo?.gender === 1 ? 'male' : userInfo?.gender === 2 ? 'female' : 'unknown'
|
||||
}
|
||||
|
||||
// 查找是否已存在微信用户
|
||||
let user = await User.findOne({
|
||||
$or: [
|
||||
{ wechatOpenid: wechatUserInfo.openid },
|
||||
{ wechatUnionid: wechatUserInfo.unionid }
|
||||
]
|
||||
})
|
||||
|
||||
if (user) {
|
||||
// 更新最后登录时间
|
||||
user.lastLoginAt = new Date()
|
||||
await user.save()
|
||||
} else {
|
||||
// 创建新用户(微信注册)
|
||||
user = new User({
|
||||
username: `wx_${wechatUserInfo.openid.slice(-8)}`,
|
||||
password: Math.random().toString(36).slice(-8), // 随机密码
|
||||
nickname: wechatUserInfo.nickname,
|
||||
avatar: wechatUserInfo.avatar,
|
||||
gender: wechatUserInfo.gender,
|
||||
wechatOpenid: wechatUserInfo.openid,
|
||||
wechatUnionid: wechatUserInfo.unionid
|
||||
})
|
||||
await user.save()
|
||||
}
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(user._id)
|
||||
|
||||
res.json(success({
|
||||
user: user.toJSON(),
|
||||
token,
|
||||
message: '微信登录成功'
|
||||
}))
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
login,
|
||||
getCurrentUser,
|
||||
updateProfile,
|
||||
changePassword,
|
||||
wechatLogin
|
||||
}
|
||||
260
backend/src/controllers/authControllerMySQL.js
Normal file
260
backend/src/controllers/authControllerMySQL.js
Normal file
@@ -0,0 +1,260 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const UserMySQL = require('../models/UserMySQL');
|
||||
const { AppError } = require('../utils/errors');
|
||||
const { success } = require('../utils/response');
|
||||
|
||||
// 生成JWT Token
|
||||
const generateToken = (userId) => {
|
||||
return jwt.sign(
|
||||
{ userId },
|
||||
process.env.JWT_SECRET || 'your-secret-key',
|
||||
{ expiresIn: process.env.JWT_EXPIRE || '7d' }
|
||||
);
|
||||
};
|
||||
|
||||
// 用户注册
|
||||
const register = async (req, res, next) => {
|
||||
try {
|
||||
const { username, password, nickname, email, phone } = req.body;
|
||||
|
||||
// 检查用户名是否已存在
|
||||
if (await UserMySQL.isUsernameExists(username)) {
|
||||
throw new AppError('用户名已存在', 400);
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
if (email && await UserMySQL.isEmailExists(email)) {
|
||||
throw new AppError('邮箱已存在', 400);
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在
|
||||
if (phone && await UserMySQL.isPhoneExists(phone)) {
|
||||
throw new AppError('手机号已存在', 400);
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
const hashedPassword = await bcrypt.hash(password, 12);
|
||||
|
||||
// 创建新用户
|
||||
const userId = await UserMySQL.create({
|
||||
username,
|
||||
password: hashedPassword,
|
||||
nickname: nickname || username,
|
||||
email,
|
||||
phone
|
||||
});
|
||||
|
||||
// 获取用户信息
|
||||
const user = await UserMySQL.findById(userId);
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(userId);
|
||||
|
||||
// 更新最后登录时间
|
||||
await UserMySQL.updateLastLogin(userId);
|
||||
|
||||
res.status(201).json(success({
|
||||
user: UserMySQL.sanitize(user),
|
||||
token,
|
||||
message: '注册成功'
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 用户登录
|
||||
const login = async (req, res, next) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
throw new AppError('用户名和密码不能为空', 400);
|
||||
}
|
||||
|
||||
// 查找用户(支持用户名、邮箱、手机号登录)
|
||||
let user = await UserMySQL.findByUsername(username);
|
||||
if (!user) {
|
||||
user = await UserMySQL.findByEmail(username);
|
||||
}
|
||||
if (!user) {
|
||||
user = await UserMySQL.findByPhone(username);
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404);
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (!UserMySQL.isActive(user)) {
|
||||
throw new AppError('账户已被禁用', 403);
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) {
|
||||
throw new AppError('密码错误', 401);
|
||||
}
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(user.id);
|
||||
|
||||
// 更新最后登录时间
|
||||
await UserMySQL.updateLastLogin(user.id);
|
||||
|
||||
res.json(success({
|
||||
user: UserMySQL.sanitize(user),
|
||||
token,
|
||||
message: '登录成功'
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前用户信息
|
||||
const getCurrentUser = async (req, res, next) => {
|
||||
try {
|
||||
const user = await UserMySQL.findById(req.userId);
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404);
|
||||
}
|
||||
|
||||
res.json(success({
|
||||
user: UserMySQL.sanitize(user)
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 更新用户信息
|
||||
const updateProfile = async (req, res, next) => {
|
||||
try {
|
||||
const { nickname, avatar, gender, birthday } = req.body;
|
||||
const updates = {};
|
||||
|
||||
if (nickname !== undefined) updates.nickname = nickname;
|
||||
if (avatar !== undefined) updates.avatar = avatar;
|
||||
if (gender !== undefined) updates.gender = gender;
|
||||
if (birthday !== undefined) updates.birthday = birthday;
|
||||
|
||||
const success = await UserMySQL.update(req.userId, updates);
|
||||
if (!success) {
|
||||
throw new AppError('更新失败', 400);
|
||||
}
|
||||
|
||||
const user = await UserMySQL.findById(req.userId);
|
||||
|
||||
res.json(success({
|
||||
user: UserMySQL.sanitize(user),
|
||||
message: '个人信息更新成功'
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 修改密码
|
||||
const changePassword = async (req, res, next) => {
|
||||
try {
|
||||
const { currentPassword, newPassword } = req.body;
|
||||
|
||||
if (!currentPassword || !newPassword) {
|
||||
throw new AppError('当前密码和新密码不能为空', 400);
|
||||
}
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
throw new AppError('新密码长度不能少于6位', 400);
|
||||
}
|
||||
|
||||
const user = await UserMySQL.findById(req.userId);
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 404);
|
||||
}
|
||||
|
||||
// 验证当前密码
|
||||
const isCurrentPasswordValid = await bcrypt.compare(currentPassword, user.password);
|
||||
if (!isCurrentPasswordValid) {
|
||||
throw new AppError('当前密码错误', 401);
|
||||
}
|
||||
|
||||
// 加密新密码
|
||||
const hashedPassword = await bcrypt.hash(newPassword, 12);
|
||||
|
||||
// 更新密码
|
||||
await UserMySQL.updatePassword(req.userId, hashedPassword);
|
||||
|
||||
res.json(success({
|
||||
message: '密码修改成功'
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 微信登录/注册
|
||||
const wechatLogin = async (req, res, next) => {
|
||||
try {
|
||||
const { code, userInfo } = req.body;
|
||||
|
||||
if (!code) {
|
||||
throw new AppError('微信授权码不能为空', 400);
|
||||
}
|
||||
|
||||
// 这里应该调用微信API获取openid和unionid
|
||||
// 模拟获取微信用户信息
|
||||
const wechatUserInfo = {
|
||||
openid: `mock_openid_${Date.now()}`,
|
||||
unionid: `mock_unionid_${Date.now()}`,
|
||||
nickname: userInfo?.nickName || '微信用户',
|
||||
avatar: userInfo?.avatarUrl || '',
|
||||
gender: userInfo?.gender === 1 ? 'male' : userInfo?.gender === 2 ? 'female' : 'unknown'
|
||||
};
|
||||
|
||||
// 查找是否已存在微信用户
|
||||
let user = await UserMySQL.findByWechatOpenid(wechatUserInfo.openid);
|
||||
|
||||
if (user) {
|
||||
// 更新最后登录时间
|
||||
await UserMySQL.updateLastLogin(user.id);
|
||||
} else {
|
||||
// 创建新用户(微信注册)
|
||||
const randomPassword = Math.random().toString(36).slice(-8);
|
||||
const hashedPassword = await bcrypt.hash(randomPassword, 12);
|
||||
|
||||
const userId = await UserMySQL.create({
|
||||
username: `wx_${wechatUserInfo.openid.slice(-8)}`,
|
||||
password: hashedPassword,
|
||||
nickname: wechatUserInfo.nickname,
|
||||
avatar: wechatUserInfo.avatar,
|
||||
gender: wechatUserInfo.gender,
|
||||
wechatOpenid: wechatUserInfo.openid,
|
||||
wechatUnionid: wechatUserInfo.unionid
|
||||
});
|
||||
|
||||
user = await UserMySQL.findById(userId);
|
||||
}
|
||||
|
||||
// 生成token
|
||||
const token = generateToken(user.id);
|
||||
|
||||
res.json(success({
|
||||
user: UserMySQL.sanitize(user),
|
||||
token,
|
||||
message: '微信登录成功'
|
||||
}));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
login,
|
||||
getCurrentUser,
|
||||
updateProfile,
|
||||
changePassword,
|
||||
wechatLogin
|
||||
};
|
||||
Reference in New Issue
Block a user