更新后端API端口和认证系统,优化数据库配置和环境变量管理
This commit is contained in:
@@ -10,7 +10,7 @@ JWT_SECRET=niumall_jwt_secret_key_2024
|
||||
JWT_EXPIRES_IN=24h
|
||||
|
||||
# 应用配置
|
||||
NODE_ENV=production
|
||||
NODE_ENV=development
|
||||
PORT=4330
|
||||
API_PREFIX=/api
|
||||
|
||||
|
||||
92
backend/add_demo_users.js
Normal file
92
backend/add_demo_users.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// 添加演示账号到数据库的脚本
|
||||
const { sequelize, ApiUser } = require('./models');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// 演示账号数据
|
||||
const demoUsers = [
|
||||
{
|
||||
username: 'admin',
|
||||
password: 'admin123',
|
||||
phone: '13800138001',
|
||||
email: 'admin@niumall.com',
|
||||
user_type: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
username: 'buyer',
|
||||
password: 'buyer123',
|
||||
phone: '13800138002',
|
||||
email: 'buyer@niumall.com',
|
||||
user_type: 'client',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
username: 'trader',
|
||||
password: 'trader123',
|
||||
phone: '13800138003',
|
||||
email: 'trader@niumall.com',
|
||||
user_type: 'supplier',
|
||||
status: 'active'
|
||||
}
|
||||
];
|
||||
|
||||
// 添加或更新演示账号
|
||||
const setupDemoUsers = async () => {
|
||||
try {
|
||||
// 测试数据库连接
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功');
|
||||
|
||||
// 为每个演示账号创建或更新记录
|
||||
for (const userData of demoUsers) {
|
||||
// 尝试通过用户名查找用户
|
||||
let user = await ApiUser.findOne({
|
||||
where: { username: userData.username }
|
||||
});
|
||||
|
||||
// 加密密码
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const passwordHash = await bcrypt.hash(userData.password, salt);
|
||||
|
||||
try {
|
||||
if (user) {
|
||||
// 用户存在,更新信息,但保留现有手机号(避免唯一约束冲突)
|
||||
await user.update({
|
||||
password_hash: passwordHash,
|
||||
email: userData.email,
|
||||
user_type: userData.user_type,
|
||||
status: userData.status
|
||||
// 不更新phone字段,避免唯一约束冲突
|
||||
});
|
||||
console.log(`✅ 成功更新用户: ${userData.username} (${userData.user_type})`);
|
||||
} else {
|
||||
// 用户不存在,创建新用户
|
||||
await ApiUser.create({
|
||||
...userData,
|
||||
password_hash: passwordHash
|
||||
});
|
||||
console.log(`✅ 成功创建用户: ${userData.username} (${userData.user_type})`);
|
||||
}
|
||||
} catch (error) {
|
||||
// 处理可能的唯一约束冲突或其他错误
|
||||
if (error.name === 'SequelizeUniqueConstraintError') {
|
||||
console.log(`⚠️ 无法创建用户 ${userData.username}: 用户名或手机号已被使用`);
|
||||
} else {
|
||||
console.error(`❌ 处理用户 ${userData.username} 时出错:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ 所有演示账号设置完成');
|
||||
} catch (error) {
|
||||
console.error('❌ 设置演示账号失败:', error.message);
|
||||
// 输出完整错误信息便于调试
|
||||
console.error(error);
|
||||
} finally {
|
||||
// 关闭数据库连接
|
||||
await sequelize.close();
|
||||
}
|
||||
};
|
||||
|
||||
// 执行脚本
|
||||
setupDemoUsers();
|
||||
262
backend/docs/openapi.json
Normal file
262
backend/docs/openapi.json
Normal file
@@ -0,0 +1,262 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "NiuMall 管理系统 API",
|
||||
"description": "NiuMall 管理系统后端API文档",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://localhost:4330/api",
|
||||
"description": "本地开发环境"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"summary": "用户登录",
|
||||
"description": "管理员用户登录认证接口,支持通过用户名或邮箱登录",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["username", "password"],
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"description": "用户名或邮箱"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"description": "用户密码"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"username": "admin",
|
||||
"password": "123456"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "登录成功",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "登录成功"
|
||||
},
|
||||
"access_token": {
|
||||
"type": "string",
|
||||
"description": "JWT访问令牌"
|
||||
},
|
||||
"token_type": {
|
||||
"type": "string",
|
||||
"example": "Bearer"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer",
|
||||
"description": "令牌过期时间(分钟)",
|
||||
"example": 1440
|
||||
},
|
||||
"user": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"example": "admin@niumall.com"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "13800138000"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "active"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "参数错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "用户名和密码不能为空"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "认证失败",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "用户名或密码错误"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "登录失败,请稍后再试"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/current": {
|
||||
"get": {
|
||||
"summary": "获取当前用户信息",
|
||||
"description": "获取当前登录用户的详细信息,需要JWT认证",
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "获取成功",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "获取用户信息成功"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"example": "admin@niumall.com"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "13800138000"
|
||||
},
|
||||
"user_type": {
|
||||
"type": "string",
|
||||
"example": "admin"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "active"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "未认证",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "未授权,请登录"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// 数据库配置
|
||||
const dbConfig = {
|
||||
development: {
|
||||
username: 'root',
|
||||
password: 'password',
|
||||
database: 'niumall_dev',
|
||||
host: '127.0.0.1',
|
||||
port: 3306,
|
||||
username: process.env.DB_USERNAME || 'root',
|
||||
password: process.env.DB_PASSWORD || 'password',
|
||||
database: process.env.DB_NAME || 'niumall_dev',
|
||||
host: process.env.DB_HOST || '127.0.0.1',
|
||||
port: process.env.DB_PORT || 3306,
|
||||
dialect: 'mysql'
|
||||
},
|
||||
production: {
|
||||
|
||||
@@ -3,7 +3,98 @@ const bcrypt = require('bcryptjs');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { successResponse, errorResponse } = require('../utils/response');
|
||||
const { jwtConfig } = require('../config/config');
|
||||
const User = require('../models/User');
|
||||
const { ApiUser } = require('../../models');
|
||||
const jsonwebtoken = require('jsonwebtoken');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 传统用户登录 - 管理系统使用
|
||||
const login = async (req, res) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
// 验证参数
|
||||
if (!username || !password) {
|
||||
return res.status(400).json(errorResponse('用户名和密码不能为空', 400));
|
||||
}
|
||||
|
||||
// 查找用户 - 支持通过用户名或邮箱登录
|
||||
let user = await ApiUser.findOne({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ username },
|
||||
{ email: username }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// 检查用户是否存在
|
||||
if (!user) {
|
||||
return res.status(401).json(errorResponse('用户名或密码错误', 401));
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
|
||||
if (!isPasswordValid) {
|
||||
return res.status(401).json(errorResponse('用户名或密码错误', 401));
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (user.status !== 'active') {
|
||||
return res.status(401).json(errorResponse('用户账号已被禁用', 401));
|
||||
}
|
||||
|
||||
// 生成JWT token
|
||||
const token = jsonwebtoken.sign(
|
||||
{
|
||||
id: user.id,
|
||||
uuid: user.uuid,
|
||||
username: user.username,
|
||||
userType: user.user_type,
|
||||
email: user.email
|
||||
},
|
||||
jwtConfig.secret,
|
||||
{ expiresIn: jwtConfig.expiresIn }
|
||||
);
|
||||
|
||||
// 准备返回的用户信息
|
||||
const userInfo = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
user_type: user.user_type,
|
||||
status: user.status,
|
||||
phone: user.phone
|
||||
};
|
||||
|
||||
// 返回响应 - 包含data字段以匹配前端期望的格式
|
||||
res.json({
|
||||
success: true,
|
||||
message: '登录成功',
|
||||
data: {
|
||||
access_token: token,
|
||||
token_type: 'Bearer',
|
||||
expires_in: parseInt(jwtConfig.expiresIn) * 60, // 转换为秒
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
phone: user.phone,
|
||||
avatar: user.avatar,
|
||||
role: user.user_type,
|
||||
status: user.status,
|
||||
createdAt: user.created_at,
|
||||
updatedAt: user.updated_at
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('用户登录失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '登录失败,请稍后再试'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 小程序用户登录
|
||||
const miniProgramLogin = async (req, res) => {
|
||||
@@ -30,7 +121,7 @@ const miniProgramLogin = async (req, res) => {
|
||||
}
|
||||
|
||||
// 生成JWT token
|
||||
const token = jwt.sign(
|
||||
const token = jsonwebtoken.sign(
|
||||
{
|
||||
id: user.id,
|
||||
uuid: user.uuid,
|
||||
@@ -62,7 +153,7 @@ const miniProgramLogin = async (req, res) => {
|
||||
// 获取当前用户信息
|
||||
const getCurrentUser = async (req, res) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.user.id);
|
||||
const user = await ApiUser.findByPk(req.user.id);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json(errorResponse('用户不存在', 404));
|
||||
@@ -86,6 +177,7 @@ const getCurrentUser = async (req, res) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
login,
|
||||
miniProgramLogin,
|
||||
getCurrentUser
|
||||
};
|
||||
@@ -1,3 +1,6 @@
|
||||
// 加载.env文件
|
||||
require('dotenv').config();
|
||||
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const helmet = require('helmet');
|
||||
@@ -5,6 +8,15 @@ const morgan = require('morgan');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
const YAML = require('yamljs');
|
||||
|
||||
// 打印环境变量用于调试
|
||||
console.log('Environment variables:');
|
||||
console.log('DB_HOST:', process.env.DB_HOST);
|
||||
console.log('DB_PORT:', process.env.DB_PORT);
|
||||
console.log('DB_USERNAME:', process.env.DB_USERNAME);
|
||||
console.log('DB_NAME:', process.env.DB_NAME);
|
||||
console.log('NODE_ENV:', process.env.NODE_ENV);
|
||||
console.log('PORT:', process.env.PORT);
|
||||
|
||||
// 数据库连接
|
||||
const sequelize = require('./config/database');
|
||||
|
||||
@@ -57,10 +69,12 @@ app.use(errorHandler);
|
||||
// 同步数据库模型
|
||||
const syncDatabase = async () => {
|
||||
try {
|
||||
await sequelize.sync({ alter: true });
|
||||
// 不修改现有表结构,只创建不存在的表
|
||||
await sequelize.sync({ force: false });
|
||||
console.log('数据库模型同步成功');
|
||||
} catch (error) {
|
||||
console.error('数据库模型同步失败:', error);
|
||||
console.log('服务器仍然会继续运行,但某些功能可能受到影响');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ const router = express.Router();
|
||||
const AuthController = require('../controllers/AuthController');
|
||||
const { authenticate } = require('../middleware/auth');
|
||||
|
||||
// 传统用户登录 - 管理系统使用
|
||||
router.post('/login', AuthController.login);
|
||||
|
||||
// 小程序用户登录
|
||||
router.post('/mini-program/login', AuthController.miniProgramLogin);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user