Jandres25/Encriptacion_PHP

GitHub: Jandres25/Encriptacion_PHP

一个自定义的轻量级 PHP MVC 认证系统,提供安全的用户登录、权限管理及完整的管理后台 CRUD 功能。

Stars: 0 | Forks: 0

# SecureAuth — PHP MVC 认证系统 [![Version](https://img.shields.io/badge/version-1.9.0-blue.svg?style=flat-square)](https://github.com/Jandres25/Encriptacion_PHP/releases/tag/1.9.0) [![Tests](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/1f821550cd185625.svg)](https://github.com/Jandres25/Encriptacion_PHP/actions/workflows/tests.yml) [![PHP Version](https://img.shields.io/badge/PHP->=8.2-777BB4.svg?style=flat-square&logo=php)](https://php.net/) [![PHPMailer](https://img.shields.io/badge/PHPMailer-^6.9-1F3B5F.svg?style=flat-square)](https://github.com/PHPMailer/PHPMailer) [![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](LICENSE) 基于 Composer、轻量级 router 和基于角色的访问控制构建的自定义 PHP MVC 认证系统。
## 功能 - 自定义 MVC 架构 — `App\Core\Router`,抽象 `Controller` 和 `Model`,通过 Composer 实现 PSR-4 自动加载 - 安全登录,使用 bcrypt 密码哈希(`password_hash()` / `password_verify()`) - 所有 POST 表单均启用 **CSRF 防护**,通过 `App\Core\Csrf` 使用 `hash_equals()` 进行 token 比对 - **防止会话固定** — 每次成功登录时执行 `session_regenerate_id(true)` - 通过 **Remember Me** 实现持久登录 — `HttpOnly` / `SameSite=Strict` cookie;token 在数据库中以 SHA-256 哈希格式存储 - 非活动状态下的自动 **会话超时**,并清理 remember cookie - 通过电子邮件进行密码恢复,使用存储为 SHA-256 哈希的一次性过期 token(PHPMailer + STARTTLS) - **用户个人资料** — 经过身份验证的用户可以在 `/profile` 修改其姓名、电子邮件和用户名,或更改密码;每个操作都有受 CSRF 保护的独立表单 - 管理员用户管理 — 具备基于角色的访问控制(`AuthMiddleware`)的完整 CRUD 功能 - `App\Config\Database` 单例 — 每个 request 单一 `\mysqli` 连接 - 用户列表的基于文件的缓存,在写入时自动失效 - **账户锁定** — N 次登录失败后自动锁定账户;可通过 `.env` 配置阈值和持续时间 - **HTTP 安全标头** — 通过 `.htaccess` 中的 `mod_headers` 设置 `X-Frame-Options`、`X-Content-Type-Options`、`Referrer-Policy`、`Content-Security-Policy` 等;HSTS 已为 HTTPS 准备就绪 - **安全会话 cookie** — `session_start_secure()` 辅助函数在每次会话启动时强制执行 `HttpOnly`、`SameSite=Strict` 以及条件性的 `Secure` 标志 - **自定义错误页面** — 契合应用设计风格的 404、403 和 500 视图;独立运行(无数据库依赖) - **集成测试套件** — 针对真实 MySQL 数据库的 40 个 PHPUnit 测试;通过 GitHub Actions 进行 CI - 所有 CRUD 和身份验证操作均使用 SweetAlert2 toast 通知 - 逐页注入 asset — 共享布局中的 `$pageStyles` / `$pageScripts` 数组 - 共享布局系统 — `header.php` / `footer.php` 接受 `$pageTitle`、`$favicon`、`$bodyClass`、`$useDataTables` - 页脚通过 `APP_VERSION` 环境变量显示应用版本 ## 环境要求 - PHP >= 8.2 - MySQL / MariaDB - 启用 `mod_rewrite` 的 Apache(推荐使用 XAMPP) - Composer - 带有应用专用密码的 Gmail 账户(或任何 SMTP 提供商) ## 安装说明 1. Clone 该 repository: ``` git clone https://github.com/Jandres25/Encriptacion_PHP.git cd Encriptacion_PHP ``` 2. 安装依赖项: ``` composer install ``` 3. 复制并配置环境文件: ``` cp .env.example .env ``` 使用您的凭证编辑 `.env`: ``` DB_HOST=localhost DB_USERNAME=root DB_PASSWORD= DB_DATABASE=login SMTP_HOST=smtp.gmail.com SMTP_USERNAME=your@gmail.com SMTP_PASSWORD=your_app_password SMTP_PORT=587 APP_URL=http://localhost/Encriptacion_PHP/public APP_TIMEZONE=America/Bogota APP_VERSION=1.9.0 CACHE_ENABLED=true CACHE_TTL_USERS=60 REMEMBER_ME_ENABLED=true REMEMBER_ME_TTL=2592000 SESSION_TIMEOUT=1800 LOGIN_LOCKOUT_ENABLED=true LOGIN_MAX_ATTEMPTS=5 LOGIN_LOCKOUT_MINUTES=15 ``` 4. 导入数据库 schema: ``` mysql -u root -p < database/schema.sql ``` 5.(可选)加载示例数据: ``` mysql -u root -p < database/seeds.sql ``` 6. 将项目放置在服务器的 web 根目录中(例如 XAMPP 中的 `htdocs/`),然后在浏览器中打开 `APP_URL`。 ## 项目结构 ``` ├── app/ │ ├── Config/ │ │ ├── autoload.php # Bootstrap: timezone, cache, DB, session, restoreFromCookie() │ │ ├── cache.php # Cache bootstrap + appCache() helper │ │ ├── config.php # Loads .env via phpdotenv; defines APP_URL + env() │ │ └── database.php # Database singleton — Database::getConnection() │ ├── Controller/ │ │ ├── AuthController.php # login, logout, forgotPassword, resetPassword │ │ ├── HomeController.php # Dashboard — applies timeout + auth middleware │ │ ├── ProfileController.php # profile(), changePassword() — any authenticated user │ │ └── UserController.php # Full user CRUD — guarded by admin middleware │ ├── Core/ │ │ ├── Auth.php # Credential verify, remember-me tokens, password reset tokens │ │ ├── Controller.php # Abstract base — render(), redirect(), verifyCsrf() │ │ ├── Csrf.php # CSRF token generation and verification │ │ ├── Model.php # Abstract base — holds protected \mysqli $db │ │ └── Router.php # GET/POST route registration and dispatch │ ├── Middleware/ │ │ └── AuthMiddleware.php # Static guards: auth(), admin(), timeout() │ ├── Model/ │ │ ├── LoginAttempt.php # Account lockout — atomic insert/update, lock check, clear │ │ └── User.php # All DB queries via MySQLi prepared statements │ └── Service/ │ └── MailerService.php # PHPMailer encapsulation — SMTP via STARTTLS ├── database/ │ ├── schema.sql # Table definitions (users, password_resets, login_attempts) │ ├── schema_test.sql # Table-only schema for test DB (no CREATE DATABASE) │ └── seeds.sql # Sample data with bcrypt-hashed passwords ├── libs/ │ └── Cache/ # File-based cache implementation ├── public/ │ ├── css/ # bootstrap.css, estilo.css, all.min.css, layout-protected.css │ ├── DataTables/ # DataTables JS bundle + Bootstrap 4 skin │ ├── img/ # Images and icons │ ├── js/ # jQuery, Bootstrap JS, Popper, SweetAlert2, users-*.js │ ├── webfonts/ # FontAwesome webfonts │ ├── .htaccess # Apache rewrite rules for clean URLs │ └── index.php # Front controller ├── routes/ │ └── web.php # All route definitions ├── storage/ │ ├── .htaccess # Require all denied — blocks direct web access to cache files │ └── cache/ # Runtime cache files (*.cache) ├── views/ │ ├── auth/ # login, forgot_password, reset_password (standalone, self-hosted assets) │ ├── errors/ # 404.php, 403.php, 500.php + layout.php (standalone, no DB dependency) │ ├── home/ # index.php — dashboard content (wrapped by shared layout) │ ├── layouts/ # header.php, footer.php, messages.php │ ├── profile/ # index.php — unified profile + change password view │ └── user/ # index, create, edit (wrapped by shared layout) ├── tests/ │ ├── bootstrap.php # Test bootstrap — loads .env.testing, never starts session │ ├── TestCase.php # Abstract base — DB connection, truncate, createUser() │ ├── Unit/ │ │ └── UserTest.php # 14 integration tests for App\Model\User │ └── Integration/ │ └── AuthTest.php # 19 integration tests for App\Core\Auth ├── .env.example # Environment variable template ├── phpunit.xml # PHPUnit 11 configuration └── composer.json # Composer dependencies and PSR-4 autoload ``` ## 用法 1. 在浏览器中打开 `http://localhost/Encriptacion_PHP/public/` 2. 使用预置的用户登录(例如用户名 `Admin`,密码 `Admin1234`) 3. 点击导航栏中的用户名以访问您的 **个人资料** — 编辑信息或更改密码 4. 管理员用户(`is_admin = 1`)可在导航栏看到 **用户** 链接 → 完整的 CRUD 5. 要找回密码,请点击登录页面上的“忘记密码?” ## URL 路由 所有路由均在 `routes/web.php` 中声明,并由 `App\Core\Router` 分发: | URL | Controller method | | --------------------------- | ---------------------------------- | | `/` | `HomeController::index()` | | `/login` | `AuthController::login()` | | `POST /logout` | `AuthController::logout()` | | `/forgot-password` | `AuthController::forgotPassword()` | | `/reset-password?token=...` | `AuthController::resetPassword()` | | `/profile` | `ProfileController::profile()` | | `POST /profile/password` | `ProfileController::changePassword()` | | `/users` | `UserController::index()` | | `/users/create` | `UserController::create()` | | `/users/edit?id=X` | `UserController::edit()` | | `POST /users/delete` | `UserController::delete()` | ## 安全 - 使用 bcrypt 对密码进行哈希处理(`PASSWORD_DEFAULT`) - 仅在成功执行 `password_verify()` 后设置会话;紧接着调用 `session_regenerate_id(true)` 以防止会话固定 - **安全会话 cookie** — `session_start_secure()` 辅助函数在每次会话启动时(包括登出和会话超时后)强制执行 `HttpOnly`、`SameSite=Strict` 以及(在 HTTPS 上)`Secure` - **HTTP 安全标头** — 通过 `public/.htaccess` 中的 `mod_headers` 设置 `X-Frame-Options: DENY`、`X-Content-Type-Options: nosniff`、`Referrer-Policy`、`Content-Security-Policy`、`Permissions-Policy`;HSTS 已注释掉,为 HTTPS 做好准备 - 所有 POST 表单均启用 **CSRF token** — 通过 `App\Core\Csrf::token()` 生成,在每个 controller 中使用 `hash_equals()` 验证;每次成功验证后 **轮换 token** - **登出仅限 POST** — 受 CSRF token 保护;防止通过 `` 或链接引发登出 CSRF - 重置 token:256 位(`bin2hex(random_bytes(32))`),有效期 1 小时,一次性使用,在数据库中以 SHA-256 哈希存储 - **防止用户枚举** — 无论该电子邮件是否已注册,`forgot-password` 始终返回相同的通用响应 - 所有数据库查询均使用 MySQLi prepared statements - **自托管 asset** — 任何视图中均无外部 CDN;消除供应链风险和 `Referer` 标头 token 泄露 - 在数据库查找之前使用 `filter_var()` 验证电子邮件 - 使用 STARTTLS 的 SMTP(端口 587) - Remember-me:cookie 中包含原始 token,数据库中存储 SHA-256 哈希 — cookie 设置为 `HttpOnly`、`SameSite=Strict`、在 HTTPS 上为 `Secure` - 每次受保护的 request 都会强制执行会话超时;清除 remember cookie 以防止静默重新登录 - 用户删除需要 POST 请求 — 无法通过 `` 或链接预取进行利用 - **管理员自我保护** — 管理员无法删除自己的账户或移除自己的 `is_admin` 标志 - **账户锁定** — 连续 5 次登录失败将锁定账户 15 分钟(可配置);仅跟踪现有用户名;成功登录或重置密码后清除锁定 - **自定义错误页面** — 404、403、500 视图均为独立运行(无数据库/会话依赖);数据库错误通过 `error_log()` 记录,绝不暴露给浏览器 ## 缓存 - 缓存的 endpoint:`/users` 列表(`App\Model\User::getAll()`) - 缓存键:`users.all` - 失效:在创建、编辑、删除和密码更新时失效 - 控制:`CACHE_ENABLED=true|false`,`CACHE_TTL_USERS=` - 存储:`storage/cache/*.cache` - 如果目录不可写,该 request 会禁用缓存并记录警告日志(无 HTTP 500) ## 测试 该项目包含一个针对真实 MySQL 数据库运行的集成测试套件(PHPUnit 11)。 ### 本地设置 ``` # 创建测试数据库 mysql -u root -p -e "CREATE DATABASE login_test;" mysql -u root -p login_test < database/schema_test.sql # 复制并配置测试环境 cp .env.testing.example .env.testing # or create it manually from .env.testing section in docs # 设置 DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE=login_test # 运行所有测试 composer test # 按 suite 运行 composer test:unit # App\Model\User + App\Model\LoginAttempt — 21 tests composer test:integration # App\Core\Auth — 19 tests ``` ### CI 测试会在每次向 `master` 发起 push 和 PR 时通过 GitHub Actions(`.github/workflows/tests.yml`)自动运行。 ## 许可证 MIT 许可证 — 详情请参阅 `LICENSE` 文件。 Jandres25 — jandrespb4@gmail.com [https://github.com/Jandres25/Encriptacion_PHP](https://github.com/Jandres25/Encriptacion_PHP)
标签:Composer, ffuf, MVC框架, OpenVAS, PHP, Syscall, Web开发