From a765da2d9c47210e145d1ce5b20baf1e228a2349 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 20 May 2024 10:51:46 +0200 Subject: [PATCH 1/3] refs #381 Crear UserInterface y configurar el security.yaml --- .env | 8 +- .gitignore | 4 + README.md | 13 + composer.json | 7 +- composer.lock | 857 +++++++++++++++++- config/bundles.php | 5 + config/packages/api_platform.yaml | 16 +- .../packages/gesdinet_jwt_refresh_token.yaml | 2 + config/packages/lexik_jwt_authentication.yaml | 8 + config/packages/security.yaml | 40 +- config/packages/web_profiler.yaml | 17 + config/packages/zenstruck_foundry.yaml | 5 + config/routes/gesdinet_jwt_refresh_token.yaml | 2 + config/routes/lexik_jwt_authentication.yaml | 3 + config/routes/web_profiler.yaml | 8 + config/services.yaml | 6 +- compose.yaml => docker-compose.yaml | 54 +- docker/Dockerfile-nginx | 2 +- docker/Dockerfile-php | 17 +- migrations/Version20240517085550.php | 31 + migrations/Version20240517101651.php | 31 + src/DataFixtures/AppFixtures.php | 17 + src/Entity/.gitignore | 0 src/Entity/RefreshToken.php | 12 + src/Entity/User.php | 108 +++ src/Factory/UserFactory.php | 55 ++ src/OpenApi/OpenApiFactory.php | 78 ++ src/Repository/UserRepository.php | 60 ++ symfony.lock | 63 ++ 29 files changed, 1473 insertions(+), 56 deletions(-) create mode 100644 config/packages/gesdinet_jwt_refresh_token.yaml create mode 100644 config/packages/lexik_jwt_authentication.yaml create mode 100644 config/packages/web_profiler.yaml create mode 100644 config/packages/zenstruck_foundry.yaml create mode 100644 config/routes/gesdinet_jwt_refresh_token.yaml create mode 100644 config/routes/lexik_jwt_authentication.yaml create mode 100644 config/routes/web_profiler.yaml rename compose.yaml => docker-compose.yaml (56%) create mode 100644 migrations/Version20240517085550.php create mode 100644 migrations/Version20240517101651.php create mode 100644 src/DataFixtures/AppFixtures.php delete mode 100644 src/Entity/.gitignore create mode 100644 src/Entity/RefreshToken.php create mode 100644 src/Entity/User.php create mode 100644 src/Factory/UserFactory.php create mode 100644 src/OpenApi/OpenApiFactory.php create mode 100644 src/Repository/UserRepository.php diff --git a/.env b/.env index be9684a..48bdf9b 100644 --- a/.env +++ b/.env @@ -25,10 +25,16 @@ APP_SECRET=e95c7f17da15ce1b03d77ad655379c34 # # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" # DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4" -DATABASE_URL="mysql://root:root@database:3306/ogcore?serverVersion=10.11.2-MariaDB&charset=utf8mb4" +DATABASE_URL="mysql://root:root@ogcore-database:3306/ogcore?serverVersion=10.11.2-MariaDB&charset=utf8mb4" #DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" ###< doctrine/doctrine-bundle ### ###> nelmio/cors-bundle ### CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' ###< nelmio/cors-bundle ### + +###> lexik/jwt-authentication-bundle ### +JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem +JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem +JWT_PASSPHRASE=8b9154df37ffa91ef9186ce095324e39e50ff3b023bb1ed34383abd019ba4515 +###< lexik/jwt-authentication-bundle ### diff --git a/.gitignore b/.gitignore index c87bc10..19d00a8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ #phpstorm .idea + +###> lexik/jwt-authentication-bundle ### +/config/jwt/*.pem +###< lexik/jwt-authentication-bundle ### diff --git a/README.md b/README.md index 37bad13..cdb79ce 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,16 @@ acceder a la siguiente URL: http://127.0.0.1:8080/api ``` Si todo ha ido bien, deberiamos ver la documentación de la API de ogCore. + +Para poder actualizar la base de datos: + +Para inicializar la base de datos: + +```sh +docker exec ogcore-php symfony console doctrine:fixtures:load --no-interaction +``` + +```sh +docker exec ogcore-php symfony console doctrine:migrations:migrate -no-interaction +``` + diff --git a/composer.json b/composer.json index 9e27354..d3ac35b 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,8 @@ "doctrine/doctrine-bundle": "^2.12", "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.1", + "gesdinet/jwt-refresh-token-bundle": "^1.3", + "lexik/jwt-authentication-bundle": "^3.0", "nelmio/cors-bundle": "^2.4", "phpdocumentor/reflection-docblock": "^5.4", "phpstan/phpdoc-parser": "^1.29", @@ -79,6 +81,9 @@ } }, "require-dev": { - "symfony/maker-bundle": "^1.59" + "doctrine/doctrine-fixtures-bundle": "^3.6", + "symfony/maker-bundle": "^1.59", + "symfony/web-profiler-bundle": "^6.4", + "zenstruck/foundry": "^1.37" } } diff --git a/composer.lock b/composer.lock index 62b2863..d56a6e3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f96df942b8e32b3a8e72cfd2e7b9f52c", + "content-hash": "d621ba18aa396cb809e0ea1ea8b815d5", "packages": [ { "name": "api-platform/core", @@ -1417,6 +1417,338 @@ }, "time": "2024-05-08T08:12:09+00:00" }, + { + "name": "gesdinet/jwt-refresh-token-bundle", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/markitosgv/JWTRefreshTokenBundle.git", + "reference": "83d687cc461b4bdae9ffc6efda97464093cae739" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/markitosgv/JWTRefreshTokenBundle/zipball/83d687cc461b4bdae9ffc6efda97464093cae739", + "reference": "83d687cc461b4bdae9ffc6efda97464093cae739", + "shasum": "" + }, + "require": { + "doctrine/persistence": "^1.3.3|^2.0|^3.0", + "lexik/jwt-authentication-bundle": "^2.0|^3.0", + "php": ">=7.4", + "symfony/config": "^4.4|^5.4|^6.0|^7.0", + "symfony/console": "^4.4|^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^4.4|^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/event-dispatcher": "^4.4|^5.4|^6.0|^7.0", + "symfony/http-foundation": "^4.4|^5.4|^6.0|^7.0", + "symfony/http-kernel": "^4.4|^5.4|^6.0|^7.0", + "symfony/polyfill-php80": "^1.15", + "symfony/property-access": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-bundle": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-core": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-http": "^4.4|^5.4|^6.0|^7.0" + }, + "conflict": { + "doctrine/mongodb-odm": "<2.2", + "doctrine/orm": "<2.7" + }, + "require-dev": { + "doctrine/annotations": "^1.13|^2.0", + "doctrine/cache": "^1.11|^2.0", + "doctrine/mongodb-odm": "^2.2", + "doctrine/orm": "^2.7", + "matthiasnoback/symfony-config-test": "^4.2|^5.0", + "matthiasnoback/symfony-dependency-injection-test": "^4.2|^5.0", + "phpunit/phpunit": "^9.5", + "symfony/cache": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-guard": "^4.4|^5.4" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Gesdinet\\JWTRefreshTokenBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marcos Gómez Vilches", + "email": "marcos@gesdinet.com" + } + ], + "description": "Implements a refresh token system over Json Web Tokens in Symfony", + "keywords": [ + "jwt refresh token bundle symfony json web" + ], + "support": { + "issues": "https://github.com/markitosgv/JWTRefreshTokenBundle/issues", + "source": "https://github.com/markitosgv/JWTRefreshTokenBundle/tree/v1.3.0" + }, + "time": "2024-01-10T19:40:34+00:00" + }, + { + "name": "lcobucci/clock", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/6f28b826ea01306b07980cb8320ab30b966cd715", + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "infection/infection": "^0.27", + "lcobucci/coding-standard": "^11.0.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.10.25", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.13", + "phpstan/phpstan-strict-rules": "^1.5.1", + "phpunit/phpunit": "^10.2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2023-11-17T17:00:27+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.27.0", + "lcobucci/clock": "^3.0", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2.9", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^10.2.6" + }, + "suggest": { + "lcobucci/clock": ">= 3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.3.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2024-04-11T23:07:54+00:00" + }, + { + "name": "lexik/jwt-authentication-bundle", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/lexik/LexikJWTAuthenticationBundle.git", + "reference": "b20c4ae7fdfe1d7422c7099a141cc9eb64627310" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lexik/LexikJWTAuthenticationBundle/zipball/b20c4ae7fdfe1d7422c7099a141cc9eb64627310", + "reference": "b20c4ae7fdfe1d7422c7099a141cc9eb64627310", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "lcobucci/clock": "^3.0", + "lcobucci/jwt": "^5.0", + "php": ">=8.2", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.4|^3.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/security-bundle": "^6.4|^7.0", + "symfony/translation-contracts": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "api-platform/core": "^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "suggest": { + "gesdinet/jwt-refresh-token-bundle": "Implements a refresh token system over Json Web Tokens in Symfony", + "spomky-labs/lexik-jose-bridge": "Provides a JWT Token encoder with encryption support" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Lexik\\Bundle\\JWTAuthenticationBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Barthe", + "email": "j.barthe@lexik.fr", + "homepage": "https://github.com/jeremyb" + }, + { + "name": "Nicolas Cabot", + "email": "n.cabot@lexik.fr", + "homepage": "https://github.com/slashfan" + }, + { + "name": "Cedric Girard", + "email": "c.girard@lexik.fr", + "homepage": "https://github.com/cedric-g" + }, + { + "name": "Dev Lexik", + "email": "dev@lexik.fr", + "homepage": "https://github.com/lexik" + }, + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com", + "homepage": "https://github.com/chalasr" + }, + { + "name": "Lexik Community", + "homepage": "https://github.com/lexik/LexikJWTAuthenticationBundle/graphs/contributors" + } + ], + "description": "This bundle provides JWT authentication for your Symfony REST API", + "homepage": "https://github.com/lexik/LexikJWTAuthenticationBundle", + "keywords": [ + "Authentication", + "JWS", + "api", + "bundle", + "jwt", + "rest", + "symfony" + ], + "support": { + "issues": "https://github.com/lexik/LexikJWTAuthenticationBundle/issues", + "source": "https://github.com/lexik/LexikJWTAuthenticationBundle/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://github.com/chalasr", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/lexik/jwt-authentication-bundle", + "type": "tidelift" + } + ], + "time": "2024-05-05T17:49:24+00:00" + }, { "name": "nelmio/cors-bundle", "version": "2.4.0", @@ -5981,6 +6313,240 @@ } ], "packages-dev": [ + { + "name": "doctrine/data-fixtures", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "bbcb74f2ac6dbe81a14b3c3687d7623490a0448f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/bbcb74f2ac6dbe81a14b3c3687d7623490a0448f", + "reference": "bbcb74f2ac6dbe81a14b3c3687d7623490a0448f", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1.0", + "doctrine/persistence": "^2.0|^3.0", + "php": "^7.4 || ^8.0" + }, + "conflict": { + "doctrine/dbal": "<3.5 || >=5", + "doctrine/orm": "<2.14 || >=4", + "doctrine/phpcr-odm": "<1.3.0" + }, + "require-dev": { + "doctrine/annotations": "^1.12 || ^2", + "doctrine/coding-standard": "^12", + "doctrine/dbal": "^3.5 || ^4", + "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", + "doctrine/orm": "^2.14 || ^3", + "ext-sqlite3": "*", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.6.13 || ^10.4.2", + "symfony/cache": "^5.4 || ^6.3 || ^7", + "symfony/var-exporter": "^5.4 || ^6.3 || ^7", + "vimeo/psalm": "^5.9" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", + "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", + "doctrine/orm": "For loading ORM fixtures", + "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\DataFixtures\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "database" + ], + "support": { + "issues": "https://github.com/doctrine/data-fixtures/issues", + "source": "https://github.com/doctrine/data-fixtures/tree/1.7.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdata-fixtures", + "type": "tidelift" + } + ], + "time": "2023-11-24T11:18:31+00:00" + }, + { + "name": "doctrine/doctrine-fixtures-bundle", + "version": "3.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/87f5d53708a3855aa018bf0a00d0d4b0ef58a956", + "reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956", + "shasum": "" + }, + "require": { + "doctrine/data-fixtures": "^1.3", + "doctrine/doctrine-bundle": "^2.2", + "doctrine/orm": "^2.14.0 || ^3.0", + "doctrine/persistence": "^2.4|^3.0", + "php": "^7.4 || ^8.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/doctrine-bridge": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0" + }, + "conflict": { + "doctrine/dbal": "< 3" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10.39", + "phpunit/phpunit": "^9.6.13", + "symfony/phpunit-bridge": "^6.3.6", + "vimeo/psalm": "^5.15" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\FixturesBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Doctrine Project", + "homepage": "https://www.doctrine-project.org" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DoctrineFixturesBundle", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "Fixture", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", + "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.6.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-fixtures-bundle", + "type": "tidelift" + } + ], + "time": "2024-05-02T18:06:53+00:00" + }, + { + "name": "fakerphp/faker", + "version": "v1.23.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b", + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1" + }, + "time": "2024-01-02T13:46:09+00:00" + }, { "name": "nikic/php-parser", "version": "v5.0.2", @@ -6130,6 +6696,295 @@ } ], "time": "2024-05-06T03:59:59+00:00" + }, + { + "name": "symfony/web-profiler-bundle", + "version": "v6.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3", + "reference": "60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "conflict": { + "symfony/form": "<5.4", + "symfony/mailer": "<5.4", + "symfony/messenger": "<5.4", + "symfony/twig-bundle": ">=7.0" + }, + "require-dev": { + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\WebProfilerBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a development tool that gives detailed information about the execution of any request", + "homepage": "https://symfony.com", + "keywords": [ + "dev" + ], + "support": { + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:22:46+00:00" + }, + { + "name": "zenstruck/assert", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/zenstruck/assert.git", + "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zenstruck/assert/zipball/60956bb6584a51c6c2ab9fa8707b7c013d770163", + "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "symfony/polyfill-php81": "^1.23", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.5", + "symfony/phpunit-bridge": "^6.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zenstruck\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + } + ], + "description": "Standalone, lightweight, framework agnostic, test assertion library.", + "homepage": "https://github.com/zenstruck/assert", + "keywords": [ + "assertion", + "phpunit", + "test" + ], + "support": { + "issues": "https://github.com/zenstruck/assert/issues", + "source": "https://github.com/zenstruck/assert/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" + } + ], + "time": "2023-12-02T09:08:04+00:00" + }, + { + "name": "zenstruck/callback", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/zenstruck/callback.git", + "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zenstruck/callback/zipball/eed9a532fd8974368e60c4a2550ed65eab7e5432", + "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.14" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zenstruck\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + } + ], + "description": "Callable wrapper to validate and inject arguments.", + "homepage": "https://github.com/zenstruck/callback", + "keywords": [ + "callable", + "callback", + "utility" + ], + "support": { + "issues": "https://github.com/zenstruck/callback/issues", + "source": "https://github.com/zenstruck/callback/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" + } + ], + "time": "2022-08-31T14:56:15+00:00" + }, + { + "name": "zenstruck/foundry", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/zenstruck/foundry.git", + "reference": "e01d77f01d2837e568ed92d226e6e778c37319a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/e01d77f01d2837e568ed92d226e6e778c37319a4", + "reference": "e01d77f01d2837e568ed92d226e6e778c37319a4", + "shasum": "" + }, + "require": { + "doctrine/persistence": "^1.3.3|^2.0|^3.0", + "fakerphp/faker": "^1.10", + "php": ">=8.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "zenstruck/assert": "^1.0", + "zenstruck/callback": "^1.1" + }, + "conflict": { + "doctrine/mongodb-odm": "2.5.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4", + "dama/doctrine-test-bundle": "^7.0|^8.0", + "doctrine/doctrine-bundle": "^2.5", + "doctrine/doctrine-migrations-bundle": "^2.2|^3.0", + "doctrine/mongodb-odm": "^2.4", + "doctrine/mongodb-odm-bundle": "^4.4.0|^5.0", + "doctrine/orm": "^2.11|^3.0", + "matthiasnoback/symfony-dependency-injection-test": "^4.1|^5.0", + "phpunit/phpunit": "^9.5.0", + "symfony/dotenv": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/maker-bundle": "^1.49", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "target-directory": "bin/tools", + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Zenstruck\\Foundry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + } + ], + "description": "A model factory library for creating expressive, auto-completable, on-demand dev/test fixtures with Symfony and Doctrine.", + "homepage": "https://github.com/zenstruck/foundry", + "keywords": [ + "Fixture", + "dev", + "doctrine", + "factory", + "faker", + "symfony", + "test" + ], + "support": { + "issues": "https://github.com/zenstruck/foundry/issues", + "source": "https://github.com/zenstruck/foundry/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" + } + ], + "time": "2024-03-20T15:09:26+00:00" } ], "aliases": [], diff --git a/config/bundles.php b/config/bundles.php index fe1d75a..3f4a386 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -9,4 +9,9 @@ return [ Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], + Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true], + Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], + Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], + Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true], + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], ]; diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index e4233dc..fe1e993 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -1,5 +1,6 @@ api_platform: - title: Hello API Platform + title: 'OgCore API' + description: 'API Documentation for OgCore' version: 1.0.0 formats: jsonld: ['application/ld+json'] @@ -7,12 +8,11 @@ api_platform: jsonld: ['application/ld+json'] jsonopenapi: ['application/vnd.openapi+json'] html: ['text/html'] - defaults: - stateless: true - cache_headers: - vary: ['Content-Type', 'Authorization', 'Origin'] - extra_properties: - standard_put: true - rfc_7807_compliant_errors: true keep_legacy_inflector: false use_symfony_listeners: true + swagger: + versions: [3] + api_keys: + apiKey: + name: Authorization + type: header \ No newline at end of file diff --git a/config/packages/gesdinet_jwt_refresh_token.yaml b/config/packages/gesdinet_jwt_refresh_token.yaml new file mode 100644 index 0000000..cd4cb5c --- /dev/null +++ b/config/packages/gesdinet_jwt_refresh_token.yaml @@ -0,0 +1,2 @@ +gesdinet_jwt_refresh_token: + refresh_token_class: App\Entity\RefreshToken diff --git a/config/packages/lexik_jwt_authentication.yaml b/config/packages/lexik_jwt_authentication.yaml new file mode 100644 index 0000000..c813308 --- /dev/null +++ b/config/packages/lexik_jwt_authentication.yaml @@ -0,0 +1,8 @@ +lexik_jwt_authentication: + secret_key: '%env(resolve:JWT_SECRET_KEY)%' + public_key: '%env(resolve:JWT_PUBLIC_KEY)%' + pass_phrase: '%env(JWT_PASSPHRASE)%' + api_platform: + check_path: /auth/login + username_path: username + password_path: password \ No newline at end of file diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 367af25..5ec2849 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -1,37 +1,39 @@ security: - # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' - # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider providers: - users_in_memory: { memory: null } + app_user_provider: + entity: + class: App\Entity\User + property: username firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: - lazy: true - provider: users_in_memory + stateless: true + provider: app_user_provider + entry_point: jwt + json_login: + check_path: auth + username_path: username + password_path: password + success_handler: lexik_jwt_authentication.handler.authentication_success + failure_handler: lexik_jwt_authentication.handler.authentication_failure + jwt: ~ + refresh_jwt: + check_path: refresh_token - # activate different ways to authenticate - # https://symfony.com/doc/current/security.html#the-firewall - - # https://symfony.com/doc/current/security/impersonating_user.html - # switch_user: true - - # Easy way to control access for large sections of your site - # Note: Only the *first* access control that matches will be used access_control: - # - { path: ^/admin, roles: ROLE_ADMIN } - # - { path: ^/profile, roles: ROLE_USER } + - { path: ^/$, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI + - { path: ^/api/docs, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI docs + - { path: ^/auth/login, roles: PUBLIC_ACCESS } + - { path: ^/auth/refresh, roles: PUBLIC_ACCESS } + - { path: ^/, roles: IS_AUTHENTICATED_FULLY } when@test: security: password_hashers: - # By default, password hashers are resource intensive and take time. This is - # important to generate secure password hashes. In tests however, secure hashes - # are not important, waste resources and increase test times. The following - # reduces the work factor to the lowest possible values. Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: algorithm: auto cost: 4 # Lowest possible value for bcrypt diff --git a/config/packages/web_profiler.yaml b/config/packages/web_profiler.yaml new file mode 100644 index 0000000..b946111 --- /dev/null +++ b/config/packages/web_profiler.yaml @@ -0,0 +1,17 @@ +when@dev: + web_profiler: + toolbar: true + intercept_redirects: false + + framework: + profiler: + only_exceptions: false + collect_serializer_data: true + +when@test: + web_profiler: + toolbar: false + intercept_redirects: false + + framework: + profiler: { collect: false } diff --git a/config/packages/zenstruck_foundry.yaml b/config/packages/zenstruck_foundry.yaml new file mode 100644 index 0000000..065bace --- /dev/null +++ b/config/packages/zenstruck_foundry.yaml @@ -0,0 +1,5 @@ +when@dev: &dev + zenstruck_foundry: + auto_refresh_proxies: true + +when@test: *dev diff --git a/config/routes/gesdinet_jwt_refresh_token.yaml b/config/routes/gesdinet_jwt_refresh_token.yaml new file mode 100644 index 0000000..e900157 --- /dev/null +++ b/config/routes/gesdinet_jwt_refresh_token.yaml @@ -0,0 +1,2 @@ +refresh_token: + path: /auth/refresh diff --git a/config/routes/lexik_jwt_authentication.yaml b/config/routes/lexik_jwt_authentication.yaml new file mode 100644 index 0000000..7ffea9e --- /dev/null +++ b/config/routes/lexik_jwt_authentication.yaml @@ -0,0 +1,3 @@ +auth: + path: /auth/login + methods: ['POST'] \ No newline at end of file diff --git a/config/routes/web_profiler.yaml b/config/routes/web_profiler.yaml new file mode 100644 index 0000000..8d85319 --- /dev/null +++ b/config/routes/web_profiler.yaml @@ -0,0 +1,8 @@ +when@dev: + web_profiler_wdt: + resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' + prefix: /_wdt + + web_profiler_profiler: + resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' + prefix: /_profiler diff --git a/config/services.yaml b/config/services.yaml index 2d6a76f..9650227 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -20,5 +20,7 @@ services: - '../src/Entity/' - '../src/Kernel.php' - # add more service definitions when explicit configuration is needed - # please note that last definitions always *replace* previous ones + App\OpenApi\OpenApiFactory: + decorates: 'api_platform.openapi.factory' + arguments: [ '@App\OpenApi\OpenApiFactory.inner' ] + autoconfigure: false diff --git a/compose.yaml b/docker-compose.yaml similarity index 56% rename from compose.yaml rename to docker-compose.yaml index 2174c29..b970b39 100644 --- a/compose.yaml +++ b/docker-compose.yaml @@ -1,25 +1,6 @@ services: - nginx: - build: - context: ./docker - dockerfile: Dockerfile-nginx - depends_on: - - php - ports: - - 8080:80 - volumes: - - ./public:/var/www/html/public:cached - - php: - build: - context: ./docker - dockerfile: Dockerfile-php - volumes: - - ./:/var/www/html - depends_on: - - database - database: + container_name: ogcore-database image: mariadb:10.11 environment: MYSQL_ROOT_PASSWORD: root @@ -27,9 +8,40 @@ services: MYSQL_PASSWORD: root MYSQL_USER: admin ports: - - 3306:3306 + - 3336:3306 volumes: - database_data:/var/lib/mysql + networks: + - ogcore-network + + nginx: + container_name: ogcore-nginx + build: + context: . + dockerfile: ./docker/Dockerfile-nginx + depends_on: + - php + ports: + - 8080:80 + volumes: + - ./public:/var/www/html/public:cached + networks: + - ogcore-network + + php: + container_name: ogcore-php + build: + context: . + dockerfile: ./docker/Dockerfile-php + volumes: + - ./:/var/www/html + depends_on: + - database + networks: + - ogcore-network volumes: database_data: + +networks: + ogcore-network: diff --git a/docker/Dockerfile-nginx b/docker/Dockerfile-nginx index ec9d167..d8d753a 100644 --- a/docker/Dockerfile-nginx +++ b/docker/Dockerfile-nginx @@ -1,2 +1,2 @@ FROM nginx:latest -COPY default.conf /etc/nginx/conf.d/default.conf \ No newline at end of file +COPY ./docker/default.conf /etc/nginx/conf.d/default.conf \ No newline at end of file diff --git a/docker/Dockerfile-php b/docker/Dockerfile-php index cc23876..6bc5967 100644 --- a/docker/Dockerfile-php +++ b/docker/Dockerfile-php @@ -1,4 +1,6 @@ FROM php:8.3-fpm-alpine +ENV COMPOSER_ALLOW_SUPERUSER=1 + # Install PHP extensions RUN docker-php-ext-install pdo mysqli pdo_mysql opcache @@ -23,5 +25,16 @@ RUN apk add --no-cache bash \ && curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.alpine.sh' | bash \ && apk add symfony-cli -RUN mkdir -p /var/www/html -WORKDIR /var/www/html \ No newline at end of file +# Expose webroot +VOLUME /var/www/html +WORKDIR /var/www/html +COPY . /var/www/html + +RUN cd /var/www/html \ + && composer install --no-interaction --no-progress --prefer-dist --no-scripts \ + && php bin/console cache:clear --no-warmup \ + && php bin/console cache:warmup \ + && php bin/console assets:install public \ + && php bin/console lexik:jwt:generate-keypair --overwrite \ + && mkdir -p var/cache var/log \ + && chmod -R 777 var/cache var/log \ No newline at end of file diff --git a/migrations/Version20240517085550.php b/migrations/Version20240517085550.php new file mode 100644 index 0000000..bec091e --- /dev/null +++ b/migrations/Version20240517085550.php @@ -0,0 +1,31 @@ +addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(180) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE user'); + } +} diff --git a/migrations/Version20240517101651.php b/migrations/Version20240517101651.php new file mode 100644 index 0000000..66bf841 --- /dev/null +++ b/migrations/Version20240517101651.php @@ -0,0 +1,31 @@ +addSql('CREATE TABLE refresh_tokens (id INT AUTO_INCREMENT NOT NULL, refresh_token VARCHAR(128) NOT NULL, username VARCHAR(255) NOT NULL, valid DATETIME NOT NULL, UNIQUE INDEX UNIQ_9BACE7E1C74F2195 (refresh_token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE refresh_tokens'); + } +} diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php new file mode 100644 index 0000000..8a74d9b --- /dev/null +++ b/src/DataFixtures/AppFixtures.php @@ -0,0 +1,17 @@ + self::ADMIN_USER]); + } +} diff --git a/src/Entity/.gitignore b/src/Entity/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/src/Entity/RefreshToken.php b/src/Entity/RefreshToken.php new file mode 100644 index 0000000..d607a63 --- /dev/null +++ b/src/Entity/RefreshToken.php @@ -0,0 +1,12 @@ + The user roles + */ + #[ORM\Column] + private array $roles = []; + + /** + * @var string The hashed password + */ + #[ORM\Column] + private ?string $password = null; + + public function getId(): ?int + { + return $this->id; + } + + public function getUsername(): ?string + { + return $this->username; + } + + public function setUsername(string $username): static + { + $this->username = $username; + + return $this; + } + + /** + * A visual identifier that represents this user. + * + * @see UserInterface + */ + public function getUserIdentifier(): string + { + return (string) $this->username; + } + + /** + * @see UserInterface + * + * @return list + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** + * @param list $roles + */ + public function setRoles(array $roles): static + { + $this->roles = $roles; + + return $this; + } + + /** + * @see PasswordAuthenticatedUserInterface + */ + public function getPassword(): string + { + return $this->password; + } + + public function setPassword(string $password): static + { + $this->password = $password; + + return $this; + } + + /** + * @see UserInterface + */ + public function eraseCredentials(): void + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } +} diff --git a/src/Factory/UserFactory.php b/src/Factory/UserFactory.php new file mode 100644 index 0000000..0e41c60 --- /dev/null +++ b/src/Factory/UserFactory.php @@ -0,0 +1,55 @@ + + */ +final class UserFactory extends ModelFactory +{ + CONST PLAIN_PASSWORD = '12345678'; + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + protected function getDefaults(): array + { + $factory = new PasswordHasherFactory([ + 'auto' => ['algorithm' => 'auto'], + ]); + $hasher = $factory->getPasswordHasher('auto'); + $hash = $hasher->hash(self::PLAIN_PASSWORD); + + return [ + 'password' => $hash, + 'roles' => [], + 'username' => self::faker()->text(180), + ]; + } + + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(User $user): void {}) + ; + } + + protected static function getClass(): string + { + return User::class; + } +} diff --git a/src/OpenApi/OpenApiFactory.php b/src/OpenApi/OpenApiFactory.php new file mode 100644 index 0000000..d7a732e --- /dev/null +++ b/src/OpenApi/OpenApiFactory.php @@ -0,0 +1,78 @@ +decorated->__invoke($context); + + $this->addRefreshToken($openApi); + + return $openApi; + } + + private function addRefreshToken(OpenApi $openApi): void + { + $openApi + ->getPaths() + ->addPath( '/auth/refresh', (new Model\PathItem())->withPost( + (new Model\Operation('postRefreshToken')) + ->withTags(['Login check']) + ->withResponses([ + Response::HTTP_OK => [ + 'description' => 'Refresh token', + 'content' => [ + 'application/json' => [ + 'schema' => [ + 'type' => 'object', + 'properties' => [ + 'token' => [ + 'type' => 'string', + 'readOnly' => true, + 'nullable' => false, + ], + 'refreshToken' => [ + 'type' => 'string', + 'readOnly' => true, + 'nullable' => false, + ] + ], + 'required' => ['token', 'refreshToken'], + ], + ], + ], + ], + ]) + ->withSummary('Create refresh token') + ->withRequestBody( + (new Model\RequestBody()) + ->withDescription('The refresh token data') + ->withContent( new \ArrayObject([ + 'application/json' => new Model\MediaType(new \ArrayObject(new \ArrayObject([ + 'type' => 'object', + 'properties' => [ + 'refreshToken' => [ + 'type' => 'string', + 'nullable' => false, + ], + ], + 'required' => ['refreshToken'], + ]))) + ])) + ->withRequired(true) + ) + )); + } +} \ No newline at end of file diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php new file mode 100644 index 0000000..4f2804e --- /dev/null +++ b/src/Repository/UserRepository.php @@ -0,0 +1,60 @@ + + */ +class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + + /** + * Used to upgrade (rehash) the user's password automatically over time. + */ + public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void + { + if (!$user instanceof User) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class)); + } + + $user->setPassword($newHashedPassword); + $this->getEntityManager()->persist($user); + $this->getEntityManager()->flush(); + } + + // /** + // * @return User[] Returns an array of User objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('u.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?User + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/symfony.lock b/symfony.lock index b59b353..3e86e9a 100644 --- a/symfony.lock +++ b/symfony.lock @@ -27,6 +27,18 @@ "src/Repository/.gitignore" ] }, + "doctrine/doctrine-fixtures-bundle": { + "version": "3.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "1f5514cfa15b947298df4d771e694e578d4c204d" + }, + "files": [ + "src/DataFixtures/AppFixtures.php" + ] + }, "doctrine/doctrine-migrations-bundle": { "version": "3.3", "recipe": { @@ -40,6 +52,32 @@ "migrations/.gitignore" ] }, + "gesdinet/jwt-refresh-token-bundle": { + "version": "1.3", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "2390b4ed5c195e0b3f6dea45221f3b7c0af523a0" + }, + "files": [ + "config/packages/gesdinet_jwt_refresh_token.yaml", + "config/routes/gesdinet_jwt_refresh_token.yaml", + "src/Entity/RefreshToken.php" + ] + }, + "lexik/jwt-authentication-bundle": { + "version": "3.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.5", + "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7" + }, + "files": [ + "config/packages/lexik_jwt_authentication.yaml" + ] + }, "nelmio/cors-bundle": { "version": "2.4", "recipe": { @@ -154,5 +192,30 @@ "files": [ "config/packages/validator.yaml" ] + }, + "symfony/web-profiler-bundle": { + "version": "6.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.1", + "ref": "e42b3f0177df239add25373083a564e5ead4e13a" + }, + "files": [ + "config/packages/web_profiler.yaml", + "config/routes/web_profiler.yaml" + ] + }, + "zenstruck/foundry": { + "version": "1.37", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.10", + "ref": "37c2f894cc098ab4c08874b80cccc8e2f8de7976" + }, + "files": [ + "config/packages/zenstruck_foundry.yaml" + ] } } -- 2.40.1 From 59545b4fedab13578ed2ddab378dbaf76ab9f691 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 21 May 2024 12:51:05 +0200 Subject: [PATCH 2/3] Updated dockerfile, and config --- README.md | 14 +++++++++++--- config/packages/security.yaml | 1 + docker/Dockerfile-php | 15 --------------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4aafac9..df93e13 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,17 @@ docker ps Y deberiamos ver algo parecido a : -- ogcore-nginx-1 -- ogcore-php-1 -- ogcore-database-1 +- ogcore-nginx +- ogcore-php +- ogcore-database + + +### Instalamos dependencias + +```sh +docker exec ogcore-php composer install +docker exec ogcore-php symfony console lexik:jwt:generate-keypair --overwrite +``` Comprobamos, que el contenedor de Nginx, tiene el puerto 8080 levantado correctamente, asi que tan solo tendremos que acceder a la siguiente URL: diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 5ec2849..978777f 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -16,6 +16,7 @@ security: entry_point: jwt json_login: check_path: auth + provider: app_user_provider username_path: username password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success diff --git a/docker/Dockerfile-php b/docker/Dockerfile-php index 6bc5967..02a3f56 100644 --- a/docker/Dockerfile-php +++ b/docker/Dockerfile-php @@ -1,7 +1,6 @@ FROM php:8.3-fpm-alpine ENV COMPOSER_ALLOW_SUPERUSER=1 - # Install PHP extensions RUN docker-php-ext-install pdo mysqli pdo_mysql opcache @@ -24,17 +23,3 @@ RUN install-php-extensions sockets RUN apk add --no-cache bash \ && curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.alpine.sh' | bash \ && apk add symfony-cli - -# Expose webroot -VOLUME /var/www/html -WORKDIR /var/www/html -COPY . /var/www/html - -RUN cd /var/www/html \ - && composer install --no-interaction --no-progress --prefer-dist --no-scripts \ - && php bin/console cache:clear --no-warmup \ - && php bin/console cache:warmup \ - && php bin/console assets:install public \ - && php bin/console lexik:jwt:generate-keypair --overwrite \ - && mkdir -p var/cache var/log \ - && chmod -R 777 var/cache var/log \ No newline at end of file -- 2.40.1 From c1ceba008d487065ebc3e7ed241486e63f8e46fd Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 22 May 2024 14:16:54 +0200 Subject: [PATCH 3/3] refs #387. Crear token y refresh_token --- config/packages/gesdinet_jwt_refresh_token.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/packages/gesdinet_jwt_refresh_token.yaml b/config/packages/gesdinet_jwt_refresh_token.yaml index cd4cb5c..855b4f7 100644 --- a/config/packages/gesdinet_jwt_refresh_token.yaml +++ b/config/packages/gesdinet_jwt_refresh_token.yaml @@ -1,2 +1,3 @@ gesdinet_jwt_refresh_token: refresh_token_class: App\Entity\RefreshToken + token_parameter_name: refreshToken -- 2.40.1