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) 的启发, 但它是一个自包含的演示项目 (并非可复用的环境)。 ![应用截图](https://raw.githubusercontent.com/walteru/symfony-react-fullstack/main/docs/screenshot-app.png) ## 架构 ``` 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开发, 全栈项目, 安全防御评估, 脚手架, 请求拦截