文字游戏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
8.8 KiB

2 weeks ago
# 后端 API 实现参考
这是一个使用 Node.js + Express 的简单后端示例,展示如何实现登录接口。
## 快速开始 (Node.js + Express)
### 1. 初始化项目
```bash
mkdir admin-backend
cd admin-backend
npm init -y
npm install express cors jsonwebtoken bcryptjs dotenv
npm install -D nodemon typescript ts-node
```
### 2. 创建 `server.js`
```javascript
const express = require('express')
const cors = require('cors')
const jwt = require('jsonwebtoken')
require('dotenv').config()
const app = express()
const PORT = process.env.PORT || 3000
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'
// 中间件
app.use(cors())
app.use(express.json())
// 模拟用户数据
const users = [
{
id: '1',
username: 'admin',
password: '123456', // 实际应该加密存储
email: 'admin@example.com',
role: 'admin'
},
{
id: '2',
username: 'user',
password: '123456',
email: 'user@example.com',
role: 'user'
}
]
// 登录接口
app.post('/api/auth/login', (req, res) => {
const { username, password } = req.body
// 验证输入
if (!username || !password) {
return res.status(400).json({
code: 400,
message: '用户名和密码不能为空'
})
}
// 查找用户
const user = users.find(u => u.username === username && u.password === password)
if (!user) {
return res.status(401).json({
code: 401,
message: '用户名或密码错误'
})
}
// 生成 JWT token
const token = jwt.sign(
{ id: user.id, username: user.username, role: user.role },
JWT_SECRET,
{ expiresIn: '7d' }
)
// 返回成功响应
res.json({
code: 200,
message: '登录成功',
data: {
token,
user: {
id: user.id,
username: user.username,
email: user.email,
role: user.role
}
}
})
})
// 登出接口
app.post('/api/auth/logout', (req, res) => {
res.json({
code: 200,
message: '登出成功'
})
})
// 获取用户信息接口 (需要认证)
app.get('/api/auth/userinfo', authenticateToken, (req, res) => {
const user = users.find(u => u.id === req.user.id)
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
})
}
res.json({
code: 200,
message: '获取成功',
data: {
id: user.id,
username: user.username,
email: user.email,
role: user.role
}
})
})
// Token 验证中间件
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[1] // Bearer <token>
if (!token) {
return res.status(401).json({
code: 401,
message: 'Token 缺失'
})
}
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) {
return res.status(401).json({
code: 401,
message: 'Token 无效或已过期'
})
}
req.user = user
next()
})
}
// 启动服务器
app.listen(PORT, () => {
console.log(\`✅ 服务器运行在 http://localhost:\${PORT}\`)
console.log(\`📝 API 文档: http://localhost:\${PORT}/api/docs\`)
})
```
### 3. 创建 `.env`
```env
PORT=3000
JWT_SECRET=your-super-secret-key-change-in-production
NODE_ENV=development
```
### 4. 运行服务器
```bash
node server.js
# 或使用 nodemon 自动重启
npx nodemon server.js
```
## API 端点说明
### 登录接口
**请求**
```
POST /api/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "123456"
}
```
**成功响应 (200)**
```json
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "1",
"username": "admin",
"email": "admin@example.com",
"role": "admin"
}
}
}
```
**错误响应 (401)**
```json
{
"code": 401,
"message": "用户名或密码错误"
}
```
### 获取用户信息接口
**请求**
```
GET /api/auth/userinfo
Authorization: Bearer <token>
```
**成功响应**
```json
{
"code": 200,
"message": "获取成功",
"data": {
"id": "1",
"username": "admin",
"email": "admin@example.com",
"role": "admin"
}
}
```
## 使用 cURL 测试
```bash
# 登录
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456"}'
# 获取用户信息
curl -X GET http://localhost:3000/api/auth/userinfo \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
```
## 使用 Postman 测试
1. 打开 Postman
2. 创建 POST 请求到 `http://localhost:3000/api/auth/login`
3. 在 Body → raw → JSON 中输入:
```json
{
"username": "admin",
"password": "123456"
}
```
4. 点击 Send
5. 复制响应中的 token
## Python Flask 示例
```python
from flask import Flask, request, jsonify
from flask_cors import CORS
from functools import wraps
import jwt
from datetime import datetime, timedelta
app = Flask(__name__)
CORS(app)
app.config['JSON_AS_ASCII'] = False
SECRET_KEY = 'your-secret-key'
# 模拟用户数据
USERS = [
{'id': '1', 'username': 'admin', 'password': '123456', 'email': 'admin@example.com', 'role': 'admin'},
{'id': '2', 'username': 'user', 'password': '123456', 'email': 'user@example.com', 'role': 'user'}
]
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not token:
return jsonify({'code': 401, 'message': 'Token 缺失'}), 401
try:
data = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
request.user_id = data['id']
except:
return jsonify({'code': 401, 'message': 'Token 无效'}), 401
return f(*args, **kwargs)
return decorated
@app.route('/api/auth/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({'code': 400, 'message': '用户名和密码不能为空'}), 400
user = next((u for u in USERS if u['username'] == username and u['password'] == password), None)
if not user:
return jsonify({'code': 401, 'message': '用户名或密码错误'}), 401
token = jwt.encode(
{'id': user['id'], 'username': user['username']},
SECRET_KEY,
algorithm='HS256'
)
return jsonify({
'code': 200,
'message': '登录成功',
'data': {
'token': token,
'user': {
'id': user['id'],
'username': user['username'],
'email': user['email'],
'role': user['role']
}
}
})
@app.route('/api/auth/userinfo', methods=['GET'])
@token_required
def get_userinfo():
user = next((u for u in USERS if u['id'] == request.user_id), None)
if not user:
return jsonify({'code': 404, 'message': '用户不存在'}), 404
return jsonify({
'code': 200,
'message': '获取成功',
'data': {
'id': user['id'],
'username': user['username'],
'email': user['email'],
'role': user['role']
}
})
if __name__ == '__main__':
app.run(debug=True, port=3000)
```
## Java Spring Boot 示例
```java
@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "*")
public class AuthController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
// 验证用户
User user = authenticateUser(request.getUsername(), request.getPassword());
if (user == null) {
return ResponseEntity.status(401).body(new ApiResponse(401, "用户名或密码错误"));
}
// 生成 JWT token
String token = JwtUtils.generateToken(user);
return ResponseEntity.ok(new ApiResponse(200, "登录成功",
new LoginResponse(token, user)));
}
@GetMapping("/userinfo")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> getUserInfo() {
User user = getCurrentUser();
return ResponseEntity.ok(new ApiResponse(200, "获取成功", user));
}
}
```
## 注意事项
1. **密码加密**:在生产环境中,必须加密存储密码(使用 bcrypt 等)
2. **HTTPS**:生产环境必须使用 HTTPS
3. **CORS**:根据前端域名配置 CORS
4. **Token 有效期**:建议设置合理的过期时间(如 7 天)
5. **错误处理**:返回统一的错误格式
6. **日志记录**:记录所有登录尝试
7. **速率限制**:防止暴力破解
## 与前端集成
1. 启动后端服务:`node server.js`
2. 启动前端开发服务:`npm run dev`
3. 前端会自动从 `http://localhost:3000/api` 调用后端接口
4. 在登录页输入 `admin / 123456` 进行测试