Compare commits
No commits in common. "fix_symfony6_preparations" and "master" have entirely different histories.
fix_symfon
...
master
|
@ -22,7 +22,7 @@
|
|||
"composer/package-versions-deprecated": "1.11.99.5",
|
||||
"doctrine/annotations": "^1.0",
|
||||
"doctrine/doctrine-bundle": "^2",
|
||||
"doctrine/doctrine-migrations-bundle": "^3",
|
||||
"doctrine/doctrine-migrations-bundle": "^2",
|
||||
"doctrine/orm": "^2",
|
||||
"excelwebzone/recaptcha-bundle": "^1.5",
|
||||
"pagerfanta/doctrine-orm-adapter": "^3.6",
|
||||
|
|
173
composer.lock
generated
173
composer.lock
generated
|
@ -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": "d075bf85a61c962f3316ab9d71fa4650",
|
||||
"content-hash": "bfa726a8284bf45a7ccbbb6600e02128",
|
||||
"packages": [
|
||||
{
|
||||
"name": "babdev/pagerfanta-bundle",
|
||||
|
@ -724,38 +724,35 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "3.3.7",
|
||||
"version": "2.13.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "9f79d4650430b582f4598fe0954ef4d52fbc0a8a"
|
||||
"reference": "c480849ca3ad6706a39c970cdfe6888fa8a058b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/9f79d4650430b582f4598fe0954ef4d52fbc0a8a",
|
||||
"reference": "9f79d4650430b582f4598fe0954ef4d52fbc0a8a",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/c480849ca3ad6706a39c970cdfe6888fa8a058b8",
|
||||
"reference": "c480849ca3ad6706a39c970cdfe6888fa8a058b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2",
|
||||
"doctrine/cache": "^1.11|^2.0",
|
||||
"doctrine/cache": "^1.0|^2.0",
|
||||
"doctrine/deprecations": "^0.5.3|^1",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"psr/cache": "^1|^2|^3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
"ext-pdo": "*",
|
||||
"php": "^7.1 || ^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "9.0.0",
|
||||
"jetbrains/phpstorm-stubs": "2022.1",
|
||||
"phpstan/phpstan": "1.7.13",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"phpunit/phpunit": "9.5.20",
|
||||
"jetbrains/phpstorm-stubs": "2021.1",
|
||||
"phpstan/phpstan": "1.4.6",
|
||||
"phpunit/phpunit": "^7.5.20|^8.5|9.5.16",
|
||||
"psalm/plugin-phpunit": "0.16.1",
|
||||
"squizlabs/php_codesniffer": "3.7.0",
|
||||
"symfony/cache": "^5.2|^6.0",
|
||||
"symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
|
||||
"vimeo/psalm": "4.23.0"
|
||||
"squizlabs/php_codesniffer": "3.6.2",
|
||||
"symfony/cache": "^4.4",
|
||||
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
|
||||
"vimeo/psalm": "4.22.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
|
@ -766,7 +763,7 @@
|
|||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "src"
|
||||
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -809,13 +806,14 @@
|
|||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlanywhere",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.3.7"
|
||||
"source": "https://github.com/doctrine/dbal/tree/2.13.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -831,7 +829,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-13T21:43:03+00:00"
|
||||
"time": "2022-05-02T20:28:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
|
@ -992,34 +990,30 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/doctrine-migrations-bundle",
|
||||
"version": "3.2.2",
|
||||
"version": "2.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/DoctrineMigrationsBundle.git",
|
||||
"reference": "3393f411ba25ade21969c33f2053220044854d01"
|
||||
"reference": "0a081b55a88259a887af7be654743a8c5f703e99"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/3393f411ba25ade21969c33f2053220044854d01",
|
||||
"reference": "3393f411ba25ade21969c33f2053220044854d01",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/0a081b55a88259a887af7be654743a8c5f703e99",
|
||||
"reference": "0a081b55a88259a887af7be654743a8c5f703e99",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/doctrine-bundle": "~1.0|~2.0",
|
||||
"doctrine/migrations": "^3.2",
|
||||
"php": "^7.2|^8.0",
|
||||
"symfony/framework-bundle": "~3.4|~4.0|~5.0|~6.0"
|
||||
"doctrine/migrations": "^2.2",
|
||||
"php": "^7.1|^8.0",
|
||||
"symfony/framework-bundle": "~3.4|~4.0|~5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^8.0",
|
||||
"doctrine/orm": "^2.6",
|
||||
"doctrine/persistence": "^1.3||^2.0",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.12",
|
||||
"phpstan/phpstan-phpunit": "^0.12",
|
||||
"phpstan/phpstan-strict-rules": "^0.12",
|
||||
"phpunit/phpunit": "^8.0|^9.0",
|
||||
"vimeo/psalm": "^4.11"
|
||||
"phpunit/phpunit": "^7.0|^8.0|^9.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
|
@ -1041,11 +1035,11 @@
|
|||
},
|
||||
{
|
||||
"name": "Doctrine Project",
|
||||
"homepage": "https://www.doctrine-project.org"
|
||||
"homepage": "http://www.doctrine-project.org"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony DoctrineMigrationsBundle",
|
||||
|
@ -1057,7 +1051,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues",
|
||||
"source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.2"
|
||||
"source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/2.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1073,7 +1067,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-01T18:08:07+00:00"
|
||||
"time": "2021-03-18T20:55:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/event-manager",
|
||||
|
@ -1408,63 +1402,49 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/migrations",
|
||||
"version": "3.5.1",
|
||||
"version": "2.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/migrations.git",
|
||||
"reference": "c0a01ddead0ccaf0282f3f4fcaa026d11918a481"
|
||||
"reference": "28d92a34348fee5daeb80879e56461b2e862fc05"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/migrations/zipball/c0a01ddead0ccaf0282f3f4fcaa026d11918a481",
|
||||
"reference": "c0a01ddead0ccaf0282f3f4fcaa026d11918a481",
|
||||
"url": "https://api.github.com/repos/doctrine/migrations/zipball/28d92a34348fee5daeb80879e56461b2e862fc05",
|
||||
"reference": "28d92a34348fee5daeb80879e56461b2e862fc05",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2",
|
||||
"doctrine/dbal": "^3.3",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
"composer/package-versions-deprecated": "^1.8",
|
||||
"doctrine/dbal": "^2.9",
|
||||
"friendsofphp/proxy-manager-lts": "^1.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"psr/log": "^1.1.3 || ^2 || ^3",
|
||||
"symfony/console": "^4.4.16 || ^5.4 || ^6.0",
|
||||
"symfony/stopwatch": "^4.4 || ^5.4 || ^6.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/orm": "<2.12"
|
||||
"php": "^7.1 || ^8.0",
|
||||
"symfony/console": "^3.4||^4.4.16||^5.0",
|
||||
"symfony/stopwatch": "^3.4||^4.0||^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"doctrine/orm": "^2.12",
|
||||
"doctrine/persistence": "^2 || ^3",
|
||||
"doctrine/sql-formatter": "^1.0",
|
||||
"ergebnis/composer-normalize": "^2.9",
|
||||
"doctrine/coding-standard": "^8.2",
|
||||
"doctrine/orm": "^2.6",
|
||||
"ext-pdo_sqlite": "*",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"phpstan/phpstan-deprecation-rules": "^1",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"phpstan/phpstan-symfony": "^1.1",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/process": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/yaml": "^4.4 || ^5.4 || ^6.0"
|
||||
"jdorn/sql-formatter": "^1.1",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.12",
|
||||
"phpstan/phpstan-phpunit": "^0.12",
|
||||
"phpstan/phpstan-strict-rules": "^0.12",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
|
||||
"symfony/cache": "^4.4. || ^5.3",
|
||||
"symfony/process": "^3.4||^4.0||^5.0",
|
||||
"symfony/yaml": "^3.4||^4.0||^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.",
|
||||
"jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command.",
|
||||
"symfony/yaml": "Allows the use of yaml for migration configuration files."
|
||||
},
|
||||
"bin": [
|
||||
"bin/doctrine-migrations"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"composer-normalize": {
|
||||
"indent-size": 4,
|
||||
"indent-style": "space"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Migrations\\": "lib/Doctrine/Migrations"
|
||||
|
@ -1493,11 +1473,12 @@
|
|||
"keywords": [
|
||||
"database",
|
||||
"dbal",
|
||||
"migrations"
|
||||
"migrations",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/migrations/issues",
|
||||
"source": "https://github.com/doctrine/migrations/tree/3.5.1"
|
||||
"source": "https://github.com/doctrine/migrations/tree/2.3.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1513,7 +1494,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-09T20:24:38+00:00"
|
||||
"time": "2021-10-19T19:55:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
|
@ -2735,16 +2716,16 @@
|
|||
},
|
||||
{
|
||||
"name": "php-http/discovery",
|
||||
"version": "1.14.3",
|
||||
"version": "1.14.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/discovery.git",
|
||||
"reference": "31d8ee46d0215108df16a8527c7438e96a4d7735"
|
||||
"reference": "c8d48852fbc052454af42f6de27635ddd916b959"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735",
|
||||
"reference": "31d8ee46d0215108df16a8527c7438e96a4d7735",
|
||||
"url": "https://api.github.com/repos/php-http/discovery/zipball/c8d48852fbc052454af42f6de27635ddd916b959",
|
||||
"reference": "c8d48852fbc052454af42f6de27635ddd916b959",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2796,9 +2777,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/discovery/issues",
|
||||
"source": "https://github.com/php-http/discovery/tree/1.14.3"
|
||||
"source": "https://github.com/php-http/discovery/tree/1.14.2"
|
||||
},
|
||||
"time": "2022-07-11T14:04:40+00:00"
|
||||
"time": "2022-05-25T07:26:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/httplug",
|
||||
|
@ -3790,16 +3771,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sentry/sentry",
|
||||
"version": "3.7.0",
|
||||
"version": "3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/getsentry/sentry-php.git",
|
||||
"reference": "877bca3f0f0ac0fc8ec0a218c6070cccea266795"
|
||||
"reference": "5b8f2934b0b20bb01da11c76985ceb5bd6c6af91"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/877bca3f0f0ac0fc8ec0a218c6070cccea266795",
|
||||
"reference": "877bca3f0f0ac0fc8ec0a218c6070cccea266795",
|
||||
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/5b8f2934b0b20bb01da11c76985ceb5bd6c6af91",
|
||||
"reference": "5b8f2934b0b20bb01da11c76985ceb5bd6c6af91",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3845,7 +3826,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.7.x-dev"
|
||||
"dev-master": "3.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -3879,7 +3860,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/getsentry/sentry-php/issues",
|
||||
"source": "https://github.com/getsentry/sentry-php/tree/3.7.0"
|
||||
"source": "https://github.com/getsentry/sentry-php/tree/3.6.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3891,7 +3872,7 @@
|
|||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2022-07-18T07:55:36+00:00"
|
||||
"time": "2022-06-27T07:58:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sentry/sentry-symfony",
|
||||
|
@ -4072,16 +4053,16 @@
|
|||
},
|
||||
{
|
||||
"name": "spiral/roadrunner",
|
||||
"version": "v2.10.7",
|
||||
"version": "v2.10.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/roadrunner-server/roadrunner.git",
|
||||
"reference": "18a7a98bcb483a680b6ebe7da8bb61e95329daf4"
|
||||
"reference": "3996ba6d12f953f808408e276f69dfcf0950e906"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/roadrunner-server/roadrunner/zipball/18a7a98bcb483a680b6ebe7da8bb61e95329daf4",
|
||||
"reference": "18a7a98bcb483a680b6ebe7da8bb61e95329daf4",
|
||||
"url": "https://api.github.com/repos/roadrunner-server/roadrunner/zipball/3996ba6d12f953f808408e276f69dfcf0950e906",
|
||||
"reference": "3996ba6d12f953f808408e276f69dfcf0950e906",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4107,9 +4088,9 @@
|
|||
"description": "RoadRunner: High-performance PHP application server, load-balancer and process manager written in Golang",
|
||||
"support": {
|
||||
"issues": "https://github.com/roadrunner-server/roadrunner/issues",
|
||||
"source": "https://github.com/roadrunner-server/roadrunner/tree/v2.10.7"
|
||||
"source": "https://github.com/roadrunner-server/roadrunner/tree/v2.10.5"
|
||||
},
|
||||
"time": "2022-07-14T09:00:44+00:00"
|
||||
"time": "2022-06-23T20:54:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spiral/roadrunner-cli",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
doctrine_migrations:
|
||||
migrations_paths:
|
||||
'DoctrineMigrations': '%kernel.project_dir%/src/Migrations'
|
||||
storage:
|
||||
table_storage:
|
||||
table_name: 'migration_versions'
|
||||
dir_name: '%kernel.project_dir%/src/Migrations'
|
||||
# namespace is arbitrary but should be different from App\Migrations
|
||||
# as migrations classes should NOT be autoloaded
|
||||
namespace: DoctrineMigrations
|
||||
|
|
|
@ -7,9 +7,6 @@ framework:
|
|||
# https://symfony.com/doc/5.4/deployment/proxies.html#but-what-if-the-ip-of-my-reverse-proxy-changes-constantly
|
||||
trusted_proxies: '%env(TRUSTED_PROXIES)%'
|
||||
|
||||
router:
|
||||
utf8: true
|
||||
|
||||
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
||||
# Remove or comment this section to explicitly disable session support.
|
||||
session:
|
||||
|
|
|
@ -6,7 +6,6 @@ security:
|
|||
class: App\Entity\User
|
||||
property: username
|
||||
manager_name: default
|
||||
enable_authenticator_manager: true
|
||||
password_hashers:
|
||||
App\Entity\User:
|
||||
algorithm: sodium
|
||||
|
@ -16,11 +15,14 @@ security:
|
|||
security: false
|
||||
api:
|
||||
pattern: ^/api/
|
||||
anonymous: ~
|
||||
stateless: true
|
||||
custom_authenticators:
|
||||
- App\Security\ApiTokenAuthenticator
|
||||
guard:
|
||||
authenticators:
|
||||
- App\Security\ApiTokenAuthenticator
|
||||
main:
|
||||
pattern: ^/
|
||||
anonymous: ~
|
||||
provider: default_provider
|
||||
form_login:
|
||||
login_path: user_auth_login
|
||||
|
@ -38,10 +40,10 @@ security:
|
|||
# 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: ^/api/v1/login$, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/api/v1/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/api/, roles: ROLE_USER }
|
||||
- { path: ^/$, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/auth/, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/register/, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/magnet/, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/auth/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/register/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/magnet/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/, roles: ROLE_USER }
|
||||
|
|
|
@ -11,7 +11,7 @@ abstract class AbstractApiController extends AbstractController
|
|||
{
|
||||
protected const DEFAULT_SERIALIZER_GROUPS = ['api'];
|
||||
|
||||
protected function createJsonResponse($data = null, array $groups = [], int $code = Response::HTTP_OK, string $message = null, string $status = ''): JsonResponse
|
||||
protected function createJsonResponse($data, array $groups = [], int $code = Response::HTTP_OK, string $message = null, string $status = ''): JsonResponse
|
||||
{
|
||||
return $this->json(new ApiResponse($data, $code, $message, $status), $code, [], [
|
||||
'groups' => array_merge(self::DEFAULT_SERIALIZER_GROUPS,$groups),
|
||||
|
|
|
@ -5,10 +5,11 @@ namespace App\Api\V1\Controller;
|
|||
|
||||
use App\Entity\{ApiToken, User};
|
||||
use App\Repository\{ApiTokenRepository, UserRepository};
|
||||
use App\Security\ApiTokenAuthenticator;
|
||||
use App\Security\Token\AuthenticatedApiToken;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\{JsonResponse, Request};
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||
|
||||
class SecurityController extends AbstractApiController
|
||||
{
|
||||
|
@ -17,18 +18,18 @@ class SecurityController extends AbstractApiController
|
|||
EntityManagerInterface $em,
|
||||
UserRepository $userRepo,
|
||||
ApiTokenRepository $tokenRepo,
|
||||
UserPasswordHasherInterface $passwordHasher,
|
||||
UserPasswordEncoderInterface $passwordEncoder
|
||||
): JsonResponse {
|
||||
$username = $request->request->get('username');
|
||||
$password = $request->request->get('password');
|
||||
|
||||
/** @var User $user */
|
||||
if (null === $user = $userRepo->findOneBy(['username' => $username])) {
|
||||
return $this->createJsonResponse(code: JsonResponse::HTTP_UNAUTHORIZED, message: 'User not found');
|
||||
return $this->createJsonResponse(null, [], JsonResponse::HTTP_UNAUTHORIZED, 'User not found');
|
||||
}
|
||||
|
||||
if (!$passwordHasher->isPasswordValid($user, $password)) {
|
||||
return $this->createJsonResponse(code: JsonResponse::HTTP_UNAUTHORIZED, message: 'Invalid password');
|
||||
if (!$passwordEncoder->isPasswordValid($user, $password)) {
|
||||
return $this->createJsonResponse(null, [], JsonResponse::HTTP_UNAUTHORIZED, 'Invalid password');
|
||||
}
|
||||
|
||||
$apiToken = new ApiToken($user);
|
||||
|
@ -37,19 +38,28 @@ class SecurityController extends AbstractApiController
|
|||
try {
|
||||
$em->flush();
|
||||
} catch (\Exception $ex) {
|
||||
return $this->createJsonResponse(code: JsonResponse::HTTP_INTERNAL_SERVER_ERROR, message: 'Token persisting error');
|
||||
return $this->createJsonResponse(null, [], JsonResponse::HTTP_INTERNAL_SERVER_ERROR, 'Token persisting error');
|
||||
}
|
||||
|
||||
return $this->createJsonResponse($apiToken->getKey());
|
||||
}
|
||||
|
||||
public function logout(Request $request, ApiTokenRepository $apiTokenRepo, EntityManagerInterface $em): JsonResponse {
|
||||
if (null === $tokenKey = ApiTokenAuthenticator::getTokenKeyFromRequest($request)) {
|
||||
return $this->createJsonResponse(null, code:JsonResponse::HTTP_INTERNAL_SERVER_ERROR, message: 'No API token provided.');
|
||||
public function logout(TokenStorageInterface $tokenStorage, ApiTokenRepository $apiTokenRepo, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
if (null === $token = $tokenStorage->getToken()) {
|
||||
return $this->createJsonResponse(null,[],JsonResponse::HTTP_INTERNAL_SERVER_ERROR, 'Can\'t retrieve user token.');
|
||||
}
|
||||
|
||||
if (!$token instanceof AuthenticatedApiToken) {
|
||||
return $this->createJsonResponse(null, [], JsonResponse::HTTP_INTERNAL_SERVER_ERROR, 'Invalid session token type retrieved.');
|
||||
}
|
||||
|
||||
if (null === $tokenKey = $token->getTokenKey()) {
|
||||
return $this->createJsonResponse(null,[],JsonResponse::HTTP_INTERNAL_SERVER_ERROR, 'Can\'t retrieve token key from the session.');
|
||||
}
|
||||
|
||||
if (null === $apiToken = $apiTokenRepo->findOneBy(['key' => $tokenKey])) {
|
||||
return $this->createJsonResponse(null, code:JsonResponse::HTTP_INTERNAL_SERVER_ERROR, message: 'API token with such key not found in the database.');
|
||||
return $this->createJsonResponse(null,[],JsonResponse::HTTP_INTERNAL_SERVER_ERROR, 'API token with such key not found in the database.');
|
||||
}
|
||||
|
||||
$em->remove($apiToken);
|
||||
|
|
|
@ -24,7 +24,7 @@ class ApiResponse
|
|||
#[Groups(['api'])]
|
||||
private ?string $message;
|
||||
|
||||
/** Response body. In case of 'error' or 'fail' contains cause or exception name. */
|
||||
/** @Response body. In case of 'error' or 'fail' contains cause or exception name. */
|
||||
#[Groups(['api'])]
|
||||
private string|object|array|null $data;
|
||||
|
||||
|
|
|
@ -4,82 +4,125 @@ declare(strict_types=1);
|
|||
namespace App\Security;
|
||||
|
||||
use App\Api\V1\DTO\ApiResponse;
|
||||
use App\Entity\User;
|
||||
use App\Repository\ApiTokenRepository;
|
||||
use Symfony\Component\HttpFoundation\{JsonResponse, Request, Response};
|
||||
use App\Security\Token\AuthenticatedApiToken;
|
||||
use Symfony\Component\HttpFoundation\{JsonResponse, Request, RequestStack, Response};
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\{AuthenticationException, CustomUserMessageAuthenticationException};
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\{Badge\UserBadge, Passport, SelfValidatingPassport};
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\{UserInterface, UserProviderInterface};
|
||||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
class ApiTokenAuthenticator extends AbstractAuthenticator
|
||||
/**
|
||||
* @deprecated Refactor to new Authenticators system @see https://gitlab.com/skobkin/magnetico-web/-/issues/26
|
||||
*/
|
||||
class ApiTokenAuthenticator extends AbstractGuardAuthenticator
|
||||
{
|
||||
public const TOKEN_HEADER = 'api-token';
|
||||
|
||||
public function __construct(
|
||||
private readonly SerializerInterface $serializer,
|
||||
private readonly ApiTokenRepository $tokenRepo,
|
||||
) {
|
||||
/** @var ApiTokenRepository */
|
||||
private $tokenRepo;
|
||||
|
||||
/** @var SerializerInterface */
|
||||
private $serializer;
|
||||
|
||||
/** @var RequestStack */
|
||||
private $requestStack;
|
||||
|
||||
public function __construct(SerializerInterface $serializer, ApiTokenRepository $tokenRepo, RequestStack $requestStack)
|
||||
{
|
||||
$this->serializer = $serializer;
|
||||
$this->tokenRepo = $tokenRepo;
|
||||
// Crutch for Guard simplified auth to retrieve 'api-token' header in the createAuthenticatedToken()
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request to decide if this authenticator should be
|
||||
* used for the request. Returning `false` will cause this authenticator
|
||||
* to be skipped.
|
||||
*
|
||||
* @see https://symfony.com/doc/6.1/security/custom_authenticator.html
|
||||
*/
|
||||
public function supports(Request $request): bool
|
||||
{
|
||||
return static::requestHasToken($request);
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
$tokenKey = static::getTokenKeyFromRequest($request);
|
||||
|
||||
if (null === $tokenKey) {
|
||||
throw new CustomUserMessageAuthenticationException('No API token provided');
|
||||
}
|
||||
|
||||
return new SelfValidatingPassport(
|
||||
new UserBadge($tokenKey, function (string $userIdentifier) {
|
||||
return $this->tokenRepo->findUserByTokenKey($userIdentifier);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
// No response object needed in token auth
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
|
||||
{
|
||||
// @todo Decouple with App\Api\V1\DTO
|
||||
$json = $this->serializer->serialize(
|
||||
new ApiResponse(null, JsonResponse::HTTP_UNAUTHORIZED, $exception->getMessageKey()),
|
||||
'json',
|
||||
['groups' => ['api']]
|
||||
);
|
||||
|
||||
return new JsonResponse($json, JsonResponse::HTTP_UNAUTHORIZED, json: true);
|
||||
}
|
||||
|
||||
public static function getTokenKeyFromRequest(Request $request): ?string
|
||||
{
|
||||
$request?->headers?->get(self::TOKEN_HEADER) ?:
|
||||
$request?->cookies?->get(self::TOKEN_HEADER) ?:
|
||||
$request?->query?->get(self::TOKEN_HEADER);
|
||||
}
|
||||
|
||||
public static function requestHasToken(Request $request): bool
|
||||
{
|
||||
// Let's also support cookies and query params for some cases like torrent clients.
|
||||
return $request->headers->has(self::TOKEN_HEADER) ||
|
||||
$request->cookies->has(self::TOKEN_HEADER) ||
|
||||
$request->query->has(self::TOKEN_HEADER);
|
||||
}
|
||||
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
return [
|
||||
'token' => $request->headers->get(self::TOKEN_HEADER) ?:
|
||||
$request->cookies->get(self::TOKEN_HEADER) ?:
|
||||
$request->query->get(self::TOKEN_HEADER),
|
||||
];
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider): ?User
|
||||
{
|
||||
if (null === $token = $credentials['token']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->tokenRepo->findUserByTokenKey($token);
|
||||
}
|
||||
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
$message = sprintf('You need to use \'%s\' in your request: %s', self::TOKEN_HEADER, $authException ? $authException->getMessage() : '');
|
||||
|
||||
$json = $this->serializer->serialize(
|
||||
new ApiResponse(null, JsonResponse::HTTP_UNAUTHORIZED, $message),
|
||||
'json',
|
||||
['groups' => ['api']]
|
||||
);
|
||||
|
||||
return new JsonResponse($json, Response::HTTP_UNAUTHORIZED,[], true);
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user)
|
||||
{
|
||||
// No credentials check needed in case of token auth
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
|
||||
{
|
||||
// No response object needed in token auth
|
||||
return null;
|
||||
}
|
||||
|
||||
public function supportsRememberMe()
|
||||
{
|
||||
// Remember me functionality don't needed in token auth
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
|
||||
{
|
||||
// @todo Decouple with App\Api\V1\DTO
|
||||
$json = $this->serializer->serialize(
|
||||
new ApiResponse(null, JsonResponse::HTTP_UNAUTHORIZED, $exception->getMessage()),
|
||||
'json',
|
||||
['groups' => ['api']]
|
||||
);
|
||||
|
||||
return new JsonResponse($json, JsonResponse::HTTP_UNAUTHORIZED,[], true);
|
||||
}
|
||||
|
||||
/** @deprecated use AuthenticatorInterface::createToken() instead */
|
||||
public function createAuthenticatedToken(UserInterface $user, $providerKey)
|
||||
{
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
$tokenKey = $request?->headers?->get(self::TOKEN_HEADER) ?:
|
||||
$request?->cookies?->get(self::TOKEN_HEADER) ?:
|
||||
$request?->query?->get(self::TOKEN_HEADER)
|
||||
;
|
||||
|
||||
return new AuthenticatedApiToken(
|
||||
$user,
|
||||
$tokenKey,
|
||||
$providerKey,
|
||||
$user->getRoles()
|
||||
);
|
||||
}
|
||||
}
|
31
src/Security/Token/AuthenticatedApiToken.php
Normal file
31
src/Security/Token/AuthenticatedApiToken.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Security\Token;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
|
||||
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
|
||||
|
||||
/**
|
||||
* This token stores ApiToken key even after eraseCredentials() called
|
||||
*
|
||||
* @deprecated Refactor to new Authenticators system @see https://gitlab.com/skobkin/magnetico-web/-/issues/26
|
||||
*/
|
||||
class AuthenticatedApiToken extends PreAuthenticatedToken implements GuardTokenInterface
|
||||
{
|
||||
/** @var string|null This token is stored only for this request and will not be erased by eraseCredentials() or serialized */
|
||||
private $tokenKey;
|
||||
|
||||
public function __construct(User $user, string $credentials, string $providerKey, array $roles = [])
|
||||
{
|
||||
parent::__construct($user, $credentials, $providerKey, $roles);
|
||||
// @todo probably separate constructor argument needed
|
||||
$this->tokenKey = $credentials;
|
||||
}
|
||||
|
||||
public function getTokenKey(): ?string
|
||||
{
|
||||
return $this->tokenKey;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue