walteru/symfony-react-fullstack
GitHub: walteru/symfony-react-fullstack
一个基于 Symfony 7.4 + React/Vite + MySQL 8 的全栈演示应用,通过 Docker 一键启动,展示 Session 认证、CSRF 防护和按用户隔离的 CRUD 实践。
Stars: 1 | Forks: 0
# Symfony + React 全栈 (演示)
基础 **全栈自包含应用**:一个基于 **Symfony 7.4** 的 REST API 和一个
原生的 **React + Vite** 单页应用 (SPA),使用 **MySQL 8**,通过 **Session (HttpOnly
cookie)** 进行身份验证,并包含按用户划分的私有任务 CRUD。只需一个
命令即可启动所有服务 (clone & run),无需在宿主机上安装 PHP、Composer 或 Node。
它是那些后端使用 Symfony、前端使用 React,且分别存放在不同仓库/服务中并通过 HTTP 通信的项目的绝佳起点。它受到了
[`Boilerplate-Docker-Symfony`](https://github.com/walteru/Boilerplate-Docker-Symfony) 的启发,
但它是一个自包含的演示项目 (并非可复用的环境)。

## 架构
```
navegador ──→ http://localhost:8099 (Vite dev server, SPA React)
│
│ Vite proxyea /api → http://api (Symfony)
▼
┌──────────┐ ┌──────────┐
│ api │ ─────→ │ db │
│ Symfony │ PDO │ MySQL 8 │
│ (Apache) │ └──────────┘
└──────────┘
```
浏览器**始终与同一个源**通信 (`localhost:8099`):Vite
会将所有以 `/api` 开头的请求转发到后端。这样,Session
(HttpOnly) cookie 就会包含在每个请求中,**完全无需依赖 CORS**。
| 服务 | 镜像 / build | 宿主机端口 | 角色 |
|------------|-----------------------|-------------|--------------------------------------|
| `frontend` | `node:20-alpine` | **8099** | React + Vite SPA (包含 `/api` 代理) |
| `api` | PHP 8.4 + Apache | **8100** | 位于 `/api` 的 Symfony REST API |
| `db` | `mysql:8.0` | 3311 | 数据库 |
## 启动 (clone & run)
环境要求:Docker 和 Docker Compose。无需其他。
```
git clone https://github.com/walteru/symfony-react-fullstack.git
cd symfony-react-fullstack
make start # o: docker compose up -d
```
在**首次启动**时,后端会安装依赖 (`composer install`),
等待 MySQL 就绪,执行迁移并加载演示数据;前端会安装其
`node_modules`。首次启动可能需要一分钟时间。
- Frontend:
- API (health):
### 演示用户 (公开凭据,非机密)
```
email: demo@example.com
password: demo1234
```
你也可以通过表单创建一个新账户。
## 身份验证与 CSRF
- **基于 HttpOnly cookie 的 Session。** 登录过程不会向
JavaScript 返回任何 token;Session 存放在浏览器无法读取的 cookie 中
(可缓解 XSS)。该 cookie 被设置为 `HttpOnly` 和 `SameSite=Lax`。
- **所有修改操作均启用 CSRF 防护。** 由于 Session 通过 cookie 传递,每个
`POST/PUT/PATCH/DELETE` 请求 (包括注册、登录和登出) 都必须包含
`X-CSRF-Token` 请求头。该 token 可通过 `GET /api/csrf-token` 获取,并与
Session 绑定:恶意网站无法读取它。前端会自动管理此过程。
- **按用户划分的私有数据。** CRUD 操作仅针对
已认证用户的任务。如果请求不存在的或他人的任务,将返回 **404**
(不加以区分,以防止泄露其他资源是否存在的信息)。
## 端点
| 方法 | 路由 | 需要认证 | 描述 |
|--------|---------------------|----------|--------------------------------------|
| GET | `/api/health` | 否 | 健康检查探针 |
| GET | `/api/csrf-token` | 否 | 用于修改操作的 CSRF token |
| POST | `/api/register` | 否 | 创建账户 |
| POST | `/api/login` | 否 | 登录 |
| POST | `/api/logout` | 是 | 登出 |
| GET | `/api/me` | — | 当前用户 (若无 Session 则返回 401) |
| GET | `/api/tasks` | 是 | 获取我的任务列表 |
| POST | `/api/tasks` | 是 | 创建任务 |
| PATCH | `/api/tasks/{id}` | 是 | 编辑自己的任务 |
| DELETE | `/api/tasks/{id}` | 是 | 删除自己的任务 |
状态码:`401` 未登录 · `403` 缺少/无效的 CSRF · `404` 不存在或他人的
资源 · `422` 无效的 payload。
## 常用命令 (`make`)
```
make start # levanta todo
make test # corre la suite PHPUnit (sobre MySQL de tests aislado)
make logs # logs en vivo
make reset-data # reinicia SOLO los datos de desarrollo (borra el volumen)
make down # baja contenedores (conserva los datos)
make rebuild # reconstruye desde cero
```
## 测试
```
make test
```
功能测试 (`WebTestCase`) 涵盖了注册、登录/登出、数据验证、
修改操作的 CSRF 防护、JSON 契约以及**用户间的数据隔离** (用户
无法查看或篡改其他用户的任务)。测试在
独立的 MySQL 测试数据库 (`app_test`) 中运行。
## 刻意限制的范围 (本项目不包含的内容)
这是一个**包含身份验证和 CRUD 的全栈基础项目**,而不是一个完整的 SaaS。为了达到演示目的,以下功能被刻意排除:
密码恢复、邮箱验证、角色控制、refresh
token、前端的生产环境构建以及部署。**Vite 代理仅用于
开发环境**:在实际部署中,前端和 API 应部署在同一个
域名下 (例如使用 Nginx) 以保持同源。
## 文章
有关此演示的历史和设计决策 (为什么选择 Session + HttpOnly
cookie 而不是存放在 localStorage 中的 JWT,Vite 代理如何
规避 CORS 困境,以及为什么所有修改操作都需要 CSRF 防护) 均在以下文章中进行了说明:
[Symfony + React 全栈:通过 Session 和 CSRF 将原生前端连接到 API](https://sincrodev.com/blog/symfony-react-full-stack-sesion-cookie-csrf/)。
## 许可证
MIT — 查看 [LICENSE](LICENSE)。
标签:Docker, ffuf, React, Symfony, Syscall, Syscalls, Web开发, 全栈项目, 安全防御评估, 脚手架, 请求拦截