hjjjj c44750e6d8 feat(部署): 添加自动化部署脚本和登录白名单功能
添加 deploy.bat 和 deploy.js 实现自动化部署流程
在 .env.example 和 auth.js 中添加登录白名单功能,支持固定验证码
更新 package.json 添加部署脚本命令
2026-03-02 16:03:55 +08:00

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 }