diff --git a/docs/customization/route_config.md b/docs/customization/route_config.md index 7b06c7d70..8596e41b6 100644 --- a/docs/customization/route_config.md +++ b/docs/customization/route_config.md @@ -29,6 +29,16 @@ service('auth')->routes($routes, ['namespace' => '\App\Controllers\Auth']); This will generate the routes with the specified namespace instead of the default Shield namespace. This can be combined with any other options, like `except`. +## Change Prefix + +If you wish, you can prefix all defined authentication routes using the `group` option. This is particularly useful if you want all your routes to be under the same root (for example, `auth/login`, `auth/register`). + +```php +service('auth')->routes($routes, ['group' => 'auth']); +``` + +This generates routes whose paths are all prefixed with `auth`. + ## Use Locale Routes You can use the `{locale}` placeholder in your routes diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 8612560f9..53ff869cc 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -427,18 +427,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/Authentication/Authenticators/SessionAuthenticatorTest.php', ]; -$ignoreErrors[] = [ - 'rawMessage' => 'Parameter #1 $headers of method Tests\\Authentication\\Filters\\AbstractFilterTestCase::withHeaders() expects array>, array{Authorization: non-falsy-string} given.', - 'identifier' => 'argument.type', - 'count' => 7, - 'path' => __DIR__ . '/tests/Authentication/Filters/HmacFilterTest.php', -]; -$ignoreErrors[] = [ - 'rawMessage' => 'Parameter #1 $headers of method Tests\\Authentication\\Filters\\JWTFilterTest::withHeaders() expects array>, array{Authorization: non-falsy-string} given.', - 'identifier' => 'argument.type', - 'count' => 1, - 'path' => __DIR__ . '/tests/Authentication/Filters/JWTFilterTest.php', -]; $ignoreErrors[] = [ 'rawMessage' => 'Implicit array creation is not allowed - variable $users might not exist.', 'identifier' => 'variable.implicitArray', diff --git a/rector.php b/rector.php index d596c8712..d2d9a6e6a 100644 --- a/rector.php +++ b/rector.php @@ -45,7 +45,6 @@ use Rector\EarlyReturn\Rector\Return_\PreparedValueToEarlyReturnRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; -use Rector\Php81\Rector\ClassMethod\NewInInitializerRector; use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\AnnotationWithValueToAttributeRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertEmptyNullableObjectToAssertInstanceofRector; @@ -138,9 +137,6 @@ // Ignore some PHPUnit rules AssertEmptyNullableObjectToAssertInstanceofRector::class, - // Ignore to prevent BC break - NewInInitializerRector::class, - // Ignore for readability RemoveNullArgOnNullDefaultParamRector::class, ]); diff --git a/src/Auth.php b/src/Auth.php index fedee8a97..d56d287b8 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -131,14 +131,16 @@ public function authenticate(array $credentials): Result * Usage (in Config/Routes.php): * - auth()->routes($routes); * - auth()->routes($routes, ['except' => ['login', 'register']]) + * - auth()->routes($routes, ['group' => 'auth']) */ public function routes(RouteCollection &$routes, array $config = []): void { $authRoutes = config('AuthRoutes')->routes; $namespace = $config['namespace'] ?? 'CodeIgniter\Shield\Controllers'; + $group = $config['group'] ?? '/'; - $routes->group('/', ['namespace' => $namespace], static function (RouteCollection $routes) use ($authRoutes, $config): void { + $routes->group($group, ['namespace' => $namespace], static function (RouteCollection $routes) use ($authRoutes, $config): void { foreach ($authRoutes as $name => $row) { if (! isset($config['except']) || ! in_array($name, $config['except'], true)) { foreach ($row as $params) { diff --git a/src/Authentication/Authenticators/JWT.php b/src/Authentication/Authenticators/JWT.php index 61deddb20..2a4c2e721 100644 --- a/src/Authentication/Authenticators/JWT.php +++ b/src/Authentication/Authenticators/JWT.php @@ -221,9 +221,7 @@ public function getTokenFromRequest(RequestInterface $request): string /** @var AuthJWT $config */ $config = config('AuthJWT'); - $tokenHeader = $request->getHeaderLine( - $config->authenticatorHeader ?? 'Authorization', - ); + $tokenHeader = $request->getHeaderLine($config->authenticatorHeader); if (str_starts_with($tokenHeader, 'Bearer')) { return trim(substr($tokenHeader, 6)); diff --git a/src/Authentication/Authenticators/Session.php b/src/Authentication/Authenticators/Session.php index 6897854b7..2b800c2a5 100644 --- a/src/Authentication/Authenticators/Session.php +++ b/src/Authentication/Authenticators/Session.php @@ -280,7 +280,7 @@ private function recordLoginAttempt( // Determine the type of ID we're using. // Standard fields would be email, username, // but any column within config('Auth')->validFields can be used. - $field = array_intersect(config('Auth')->validFields ?? [], array_keys($credentials)); + $field = array_intersect(config('Auth')->validFields, array_keys($credentials)); if (count($field) !== 1) { throw new InvalidArgumentException('Invalid credentials passed to recordLoginAttempt.'); diff --git a/src/Config/Auth.php b/src/Config/Auth.php index b4f007b2c..c6c27bf1e 100644 --- a/src/Config/Auth.php +++ b/src/Config/Auth.php @@ -29,7 +29,7 @@ class Auth extends BaseConfig { - /** + /* * //////////////////////////////////////////////////////////////////// * AUTHENTICATION * //////////////////////////////////////////////////////////////////// @@ -378,7 +378,7 @@ class Auth extends BaseConfig */ public int $hashCost = 12; - /** + /* * //////////////////////////////////////////////////////////////////// * OTHER SETTINGS * //////////////////////////////////////////////////////////////////// diff --git a/tests/Authentication/MagicLinkTest.php b/tests/Authentication/MagicLinkTest.php index 19e5c52f8..f421a03fd 100644 --- a/tests/Authentication/MagicLinkTest.php +++ b/tests/Authentication/MagicLinkTest.php @@ -75,9 +75,7 @@ public function testMagicLinkSubmitBadEmail(): void public function testMagicLinkSubmitSuccess(): void { - /** - * @phpstan-var User - */ + /** @phpstan-var User $user */ $user = fake(UserModel::class); $user->createEmailIdentity(['email' => 'foo@example.com', 'password' => 'secret123']); @@ -105,9 +103,8 @@ public function testMagicLinkVerifyNoToken(): void public function testMagicLinkVerifyExpired(): void { $identities = new UserIdentityModel(); - /** - * @phpstan-var User - */ + + /** @phpstan-var User $user */ $user = fake(UserModel::class); $user->createEmailIdentity(['email' => 'foo@example.com', 'password' => 'secret123']); $identities->insert([ diff --git a/tests/Language/AbstractTranslationTestCase.php b/tests/Language/AbstractTranslationTestCase.php index 6085443e9..38ae4138a 100644 --- a/tests/Language/AbstractTranslationTestCase.php +++ b/tests/Language/AbstractTranslationTestCase.php @@ -220,8 +220,7 @@ final public function testAllIncludedLanguageKeysAreTranslated(string $locale): { // These keys are usually not translated because they contain either // universal abbreviations or simply combine parameters with signs. - static $excludedKeyTranslations = [ - ]; + static $excludedKeyTranslations = []; $excludedKeys = array_unique(array_merge($excludedKeyTranslations, $this->excludedLocaleKeyTranslations)); $availableSets = array_intersect($this->expectedSets(), $this->foundSets($locale)); diff --git a/tests/Unit/AuthRoutesTest.php b/tests/Unit/AuthRoutesTest.php index d4e568121..b8b5747f6 100644 --- a/tests/Unit/AuthRoutesTest.php +++ b/tests/Unit/AuthRoutesTest.php @@ -80,4 +80,24 @@ public function testRoutesCustomNamespace(): void $this->assertSame('\Auth\RegisterController::registerView', $routes['register']); } + + public function testRoutesCustomPrefix(): void + { + $collection = single_service('routes'); + $auth = service('auth'); + + $auth->routes($collection, ['group' => 'auth']); + + if (version_compare(CodeIgniter::CI_VERSION, '4.5') >= 0) { + $routes = $collection->getRoutes('GET'); + } else { + $routes = $collection->getRoutes('get'); + } + + $this->assertArrayHasKey('auth/register', $routes); + $this->assertArrayHasKey('auth/login', $routes); + $this->assertArrayHasKey('auth/login/magic-link', $routes); + $this->assertArrayHasKey('auth/logout', $routes); + $this->assertArrayHasKey('auth/auth/a/show', $routes); + } } diff --git a/tests/Unit/UserIdentityModelTest.php b/tests/Unit/UserIdentityModelTest.php index 00133a98a..e552a3b19 100644 --- a/tests/Unit/UserIdentityModelTest.php +++ b/tests/Unit/UserIdentityModelTest.php @@ -85,7 +85,6 @@ public function testCreateCodeIdentityThrowsExceptionIfUniqueCodeIsNotGot(): voi public function testForceMultiplePasswordReset(): void { - /** @var Fabricator $fabricator */ $fabricator = new Fabricator(UserIdentityModel::class); $fabricator->create(10);