添加 deploy.bat 和 deploy.js 实现自动化部署流程 在 .env.example 和 auth.js 中添加登录白名单功能,支持固定验证码 更新 package.json 添加部署脚本命令
182 lines
5.3 KiB
JavaScript
182 lines
5.3 KiB
JavaScript
const jwt = require('jsonwebtoken')
|
|
const { sendVerificationCode, verifyCode } = require('../services/auth')
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production'
|
|
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d'
|
|
|
|
const WHITELIST_CODE = process.env.WHITELIST_CODE || '888888'
|
|
const WHITELIST_EMAILS = (process.env.WHITELIST_EMAILS || '')
|
|
.split(',').map(e => e.trim().toLowerCase()).filter(Boolean)
|
|
|
|
function createAuthRoutes(db) {
|
|
const usersCollection = db.collection('users')
|
|
|
|
return {
|
|
async sendCode(req, res) {
|
|
try {
|
|
const { email } = req.body
|
|
|
|
if (!email) {
|
|
return res.status(400).json({ success: false, error: '邮箱不能为空' })
|
|
}
|
|
|
|
if (WHITELIST_EMAILS.includes(email.toLowerCase())) {
|
|
return res.json({ success: true, message: '验证码已发送' })
|
|
}
|
|
|
|
const result = await sendVerificationCode(db, email.toLowerCase())
|
|
|
|
if (!result.success) {
|
|
return res.status(400).json(result)
|
|
}
|
|
|
|
res.json({ success: true, message: '验证码已发送' })
|
|
} catch (err) {
|
|
console.error('[Auth] Send code error:', err)
|
|
res.status(500).json({ success: false, error: err.message })
|
|
}
|
|
},
|
|
|
|
async login(req, res) {
|
|
try {
|
|
const { email, code, nickname } = req.body
|
|
|
|
if (!email || !code) {
|
|
return res.status(400).json({ success: false, error: '邮箱和验证码不能为空' })
|
|
}
|
|
|
|
const emailLower = email.toLowerCase()
|
|
|
|
if (WHITELIST_EMAILS.includes(emailLower)) {
|
|
if (code !== WHITELIST_CODE) {
|
|
return res.status(400).json({ success: false, error: '验证码错误' })
|
|
}
|
|
} else {
|
|
const verifyResult = await verifyCode(db, emailLower, code)
|
|
if (!verifyResult.success) {
|
|
return res.status(400).json(verifyResult)
|
|
}
|
|
}
|
|
|
|
let user = await usersCollection.findOne({ email: emailLower })
|
|
|
|
if (!user) {
|
|
const newUser = {
|
|
email: emailLower,
|
|
nickname: nickname || emailLower.split('@')[0],
|
|
avatar: null,
|
|
created_at: new Date(),
|
|
updated_at: new Date(),
|
|
last_login: new Date(),
|
|
status: 'active'
|
|
}
|
|
const result = await usersCollection.insertOne(newUser)
|
|
user = { ...newUser, _id: result.insertedId }
|
|
} else {
|
|
await usersCollection.updateOne(
|
|
{ _id: user._id },
|
|
{
|
|
$set: {
|
|
last_login: new Date(),
|
|
updated_at: new Date()
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
{
|
|
userId: user._id.toString(),
|
|
email: user.email
|
|
},
|
|
JWT_SECRET,
|
|
{ expiresIn: JWT_EXPIRES_IN }
|
|
)
|
|
|
|
res.json({
|
|
success: true,
|
|
token,
|
|
user: {
|
|
id: user._id,
|
|
email: user.email,
|
|
nickname: user.nickname,
|
|
avatar: user.avatar,
|
|
created_at: user.created_at
|
|
}
|
|
})
|
|
} catch (err) {
|
|
console.error('[Auth] Login error:', err)
|
|
res.status(500).json({ success: false, error: err.message })
|
|
}
|
|
},
|
|
|
|
async verifyToken(req, res, next) {
|
|
try {
|
|
const authHeader = req.headers.authorization
|
|
|
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
return res.status(401).json({ success: false, error: '未登录' })
|
|
}
|
|
|
|
const token = authHeader.split(' ')[1]
|
|
|
|
try {
|
|
const decoded = jwt.verify(token, JWT_SECRET)
|
|
const user = await usersCollection.findOne({ _id: new (require('mongodb').ObjectId)(decoded.userId) })
|
|
|
|
if (!user) {
|
|
return res.status(401).json({ success: false, error: '用户不存在' })
|
|
}
|
|
|
|
req.user = {
|
|
id: user._id.toString(),
|
|
email: user.email,
|
|
nickname: user.nickname,
|
|
avatar: user.avatar
|
|
}
|
|
next()
|
|
} catch (jwtErr) {
|
|
return res.status(401).json({ success: false, error: 'Token无效或已过期' })
|
|
}
|
|
} catch (err) {
|
|
console.error('[Auth] Verify token error:', err)
|
|
res.status(500).json({ success: false, error: err.message })
|
|
}
|
|
},
|
|
|
|
async getProfile(req, res) {
|
|
try {
|
|
res.json({ success: true, user: req.user })
|
|
} catch (err) {
|
|
console.error('[Auth] Get profile error:', err)
|
|
res.status(500).json({ success: false, error: err.message })
|
|
}
|
|
},
|
|
|
|
async updateProfile(req, res) {
|
|
try {
|
|
const { nickname, avatar } = req.body
|
|
const updateData = { updated_at: new Date() }
|
|
|
|
if (nickname) updateData.nickname = nickname
|
|
if (avatar) updateData.avatar = avatar
|
|
|
|
await usersCollection.updateOne(
|
|
{ _id: new (require('mongodb').ObjectId)(req.user.id) },
|
|
{ $set: updateData }
|
|
)
|
|
|
|
res.json({
|
|
success: true,
|
|
user: { ...req.user, ...updateData }
|
|
})
|
|
} catch (err) {
|
|
console.error('[Auth] Update profile error:', err)
|
|
res.status(500).json({ success: false, error: err.message })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { createAuthRoutes }
|