一、接口安全、限流 & 防御策略
1️⃣ 恶意请求
- 暴力刷接口(爆破登录)
- 短时间大量请求(DDOS / CC攻击)
👉 解决:限流(Rate Limit)
2️⃣ 非法数据
- SQL 注入
- XSS 攻击
👉 解决:输入校验 + 过滤
3️⃣ 非授权访问
- 没登录访问接口
- Token伪造
👉 解决:JWT + 权限控制(你第11天已经学了)
4️⃣ 敏感信息泄露
- 报错返回数据库信息
- 返回用户隐私字段
👉 解决:统一错误处理 + 数据脱敏
二、实战项目整合
bash
day14-project/
│
├── app.js
│
├── config/
│ └── index.js # 环境配置
│
├── controllers/ # 控制器(处理请求)
│ └── user.controller.js
│
├── services/ # 业务逻辑层
│ └── user.service.js
│
├── models/ # 数据层
│ └── user.model.js
│
├── routes/ # 路由层
│ └── user.routes.js
│
├── middlewares/ # 中间件
│ ├── auth.middleware.js # JWT认证
│ ├── rateLimit.middleware.js # 限流
│ └── error.middleware.js # 错误统一处理
├── utils/
│ └── logger.js # 日志系统
│
├── logs/ # 日志文件目录
│
├── .env # 环境变量
└── package.json
bash
请求
↓
routes(路由分发)
↓
controller(接收请求)
↓
service(业务逻辑)
↓
model(数据库)
↓
返回结果
↓
error middleware(统一错误)
↓
logger(记录日志)
📄 app.js(项目入口)
javascript
/**
* 应用入口文件
* 作用:
* 1. 创建 Express 实例
* 2. 注册中间件
* 3. 注册路由
* 4. 启动服务
*/
const express = require('express')
const app = express()
// 引入配置
const config = require('./config')
// 引入日志工具
const logger = require('./utils/logger')
// 引入路由
const userRoutes = require('./routes/user.routes')
// 引入错误处理中间件(必须最后注册)
const errorHandler = require('./middlewares/error.middleware')
/**
* 内置中间件
* 解析 JSON 请求体
*/
app.use(express.json())
/**
* 路由模块
* 所有 /api/users 开头的请求都会进入 userRoutes
*/
app.use('/api/users', userRoutes)
/**
* 全局错误处理中间件
* ⚠️ 必须放在所有路由之后
*/
app.use(errorHandler)
/**
* 启动服务
*/
app.listen(config.port, () => {
logger.info(`Server running on port ${config.port}`)
})
📁 config/index.js(配置中心)
javascript
/**
* 配置管理模块
* 作用:
* 统一管理环境变量
* 避免在代码中写死配置(硬编码)
*/
require('dotenv').config()
module.exports = {
// 服务端口
port: process.env.PORT,
// JWT 密钥
jwtSecret: process.env.JWT_SECRET,
// 数据库配置
db: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
}
}
📁 routes/user.routes.js(路由层)
javascript
/**
* 路由层
* 作用:
* 定义 API 路径 + 对应的 controller
*/
const express = require('express')
const router = express.Router()
// 引入控制器
const userController = require('../controllers/user.controller')
// 引入中间件
const authMiddleware = require('../middlewares/auth.middleware')
const rateLimit = require('../middlewares/rateLimit.middleware')
/**
* 登录接口
* POST /api/users/login
*/
router.post('/login', rateLimit, userController.login)
/**
* 示例:需要登录才能访问
*/
router.get('/profile', authMiddleware, (req, res) => {
res.json({
message: 'Protected data',
user: req.user
})
})
module.exports = router
📁 controllers/user.controller.js(控制器)
javascript
/**
* 控制器层(Controller)
* 作用:
* 1. 接收请求参数
* 2. 调用 service
* 3. 返回响应
* 4. 不写业务逻辑!
*/
const userService = require('../services/user.service')
/**
* 用户登录
*/
exports.login = async (req, res, next) => {
try {
// 调用业务逻辑
const result = await userService.login(req.body)
// 返回结果
res.json(result)
} catch (err) {
/**
* ⚠️ 关键点:
* 所有错误统一交给 error.middleware
*/
next(err)
}
}
📁 services/user.service.js(业务逻辑层)
javascript
/**
* 业务逻辑层(Service)
* 作用:
* 1. 写核心业务逻辑
* 2. 可以调用 model(数据库)
* 3. 可以抛出业务错误
*/
const jwt = require('jsonwebtoken')
const config = require('../config')
/**
* 登录逻辑
*/
exports.login = async ({ username }) => {
/**
* 参数校验
*/
if (!username) {
const error = new Error('Username is required')
error.status = 400
throw error
}
/**
* 实际项目中:
* 这里应该查数据库验证用户
*/
/**
* 生成 JWT token
*/
const token = jwt.sign(
{ username },
config.jwtSecret,
{ expiresIn: '1h' }
)
return {
message: 'Login success',
token
}
}
📁 models/user.model.js(数据层)
javascript
/**
* 数据层(Model)
* 作用:
* 1. 专门操作数据库
* 2. 不写业务逻辑
*/
const sql = require('mssql')
const config = require('../config')
/**
* 示例:根据用户名查询用户
*/
exports.findUserByUsername = async (username) => {
try {
const pool = await sql.connect(config.db)
const result = await pool
.request()
.input('username', sql.VarChar, username)
.query('SELECT * FROM users WHERE username = @username')
return result.recordset[0]
} catch (err) {
throw err
}
}
📁 middlewares/auth.middleware.js(JWT认证)
javascript
/**
* JWT 鉴权中间件
* 作用:
* 验证用户是否登录
*/
const jwt = require('jsonwebtoken')
const config = require('../config')
module.exports = (req, res, next) => {
// 获取 token
const token = req.headers.authorization
if (!token) {
return res.status(401).json({ message: 'No token' })
}
try {
// 验证 token
const decoded = jwt.verify(token, config.jwtSecret)
// 挂载用户信息
req.user = decoded
next()
} catch (err) {
res.status(401).json({ message: 'Invalid token' })
}
}
📁 middlewares/rateLimit.middleware.js(限流)
javascript
/**
* 限流中间件
* 作用:
* 防止接口被刷(防攻击)
*/
const rateLimit = require('express-rate-limit')
module.exports = rateLimit({
windowMs: 60 * 1000, // 1分钟
max: 5, // 最多5次请求
message: 'Too many requests, please try again later'
})
📁 middlewares/error.middleware.js(全局错误处理)
javascript
/**
* 全局错误处理中间件
* 作用:
* 统一处理所有错误
*/
const logger = require('../utils/logger')
module.exports = (err, req, res, next) => {
/**
* 记录错误日志
*/
logger.error(err.message)
/**
* 返回统一格式
*/
res.status(err.status || 500).json({
message: err.message || 'Internal Server Error'
})
}
📁 utils/logger.js(日志系统)
javascript
/**
* 日志系统(Winston)
* 作用:
* 1. 记录错误日志
* 2. 记录运行日志
*/
const { createLogger, format, transports } = require('winston')
const logger = createLogger({
level: 'info',
format: format.combine(
format.timestamp(),
format.printf(({ level, message, timestamp }) => {
return `${timestamp} [${level}] ${message}`
})
),
transports: [
// 控制台输出
new transports.Console(),
// 错误日志
new transports.File({
filename: 'logs/error.log',
level: 'error'
}),
// 所有日志
new transports.File({
filename: 'logs/combined.log'
})
]
})
module.exports = logger
📄 .env(环境变量)
javascript
# 服务端口
PORT=3000
# JWT 密钥
JWT_SECRET=supersecret
# 数据库配置
DB_HOST=localhost
DB_USER=sa
DB_PASSWORD=123456
DB_NAME=testdb