-
WitER Junior Member
 
-
Posts: 10
Threads: 1
Joined: Apr 2021
Reputation:
0
11-27-2024, 11:14 PM
(This post was last modified: 11-28-2024, 12:45 AM by WitER.)
Good day!
I want restrict routing groups by shield permissions , but filter working only for parent group. In children groups permission filter not working. Where my bad?
CI 4.5.5 \ Shield 1.1.0
PHP Code: $routes->group('admin', ['filter' => 'permission:admin.access'], static function (RouteCollection $routes) { // permission:admin.access is working $routes->get('/', 'Admin::index', ['as' => 'admin']);
$routes->group('users', ['filter' => 'permission:users.access'], static function (RouteCollection $routes) { // permission:users.access is ignoring $routes->get('/', 'Auth\Users::index', ['as' => 'admin-users']); }); });
-
InsiteFX Super Moderator
     
-
Posts: 6,713
Threads: 342
Joined: Oct 2014
Reputation:
246
Code: For this to work you have to enable multiple filters in Config/Feature.php
PHP Code: public bool $multipleFilters = true;
What did you Try? What did you Get? What did you Expect?
Joined CodeIgniter Community 2009. ( Skype: insitfx )
-
WitER Junior Member
 
-
Posts: 10
Threads: 1
Joined: Apr 2021
Reputation:
0
(11-28-2024, 09:55 PM)InsiteFX Wrote: Code: For this to work you have to enable multiple filters in Config/Feature.php
PHP Code: public bool $multipleFilters = true;
It's not work for me, and search by multipleFilters in project or vendor directory not founding any using for this parameter.
Maybe there are any other ideas? Or is there something wrong with my configuration in principle?
-
WitER Junior Member
 
-
Posts: 10
Threads: 1
Joined: Apr 2021
Reputation:
0
11-30-2024, 03:36 AM
(This post was last modified: 11-30-2024, 03:36 AM by WitER.)
(11-29-2024, 10:29 PM)InsiteFX Wrote: !Important
Since v4.5.0, Multiple Filters are always enabled. Prior to v4.5.0, Multiple Filters were disabled by
default. If you want to use with prior to v4.5.0, See Upgrading from 4.1.4 to 4.1.5 for the details.
Yep, but i created project from v4.5.0, now 4.5.5 and filters for nested routing groups does not work.
-
ozornick Antispam Moderator
     
-
Posts: 561
Threads: 29
Joined: Jul 2022
Reputation:
27
-
WitER Junior Member
 
-
Posts: 10
Threads: 1
Joined: Apr 2021
Reputation:
0
(12-01-2024, 09:26 PM)ozornick Wrote: See in console or test controller command():
spark routes
spark filter:check /users
https://codeigniter.com/user_guide/incom...lter-check
spark routes
Code: CodeIgniter v4.5.5 Command Line Tool - Server Time: 2024-12-02 11:47:12 UTC+00:00
+--------+------------------------------+-------------------------------------+--------------------------------------------------------------------+------------------------------------+-----------------------+
| Method | Route | Name | Handler | Before Filters | After Filters |
+--------+------------------------------+-------------------------------------+--------------------------------------------------------------------+------------------------------------+-----------------------+
| GET | / | main | \App\Controllers\Home::index | csrf | |
| GET | profile | » | \App\Controllers\Auth\Profile::index | csrf session session | session |
| GET | profile/(.*) | profile-tab | \App\Controllers\Auth\Profile::index/$1 | csrf session session | session |
| GET | admin | » | \App\Controllers\Admin::index | csrf session permission | permission |
| GET | admin/users | admin-users | \App\Controllers\Auth\Users::index | csrf session permission permission | permission permission |
| GET | register | » | \CodeIgniter\Shield\Controllers\RegisterController::registerView | csrf auth-rates | |
| GET | login | » | \CodeIgniter\Shield\Controllers\LoginController::loginView | csrf auth-rates | |
| GET | login/magic-link | magic-link | \CodeIgniter\Shield\Controllers\MagicLinkController::loginView | csrf auth-rates | |
| GET | login/verify-magic-link | verify-magic-link | \CodeIgniter\Shield\Controllers\MagicLinkController::verify | csrf auth-rates | |
| GET | logout | » | \CodeIgniter\Shield\Controllers\LoginController::logoutAction | csrf | |
| GET | auth/a/show | auth-action-show | \CodeIgniter\Shield\Controllers\ActionController::show | csrf auth-rates | |
| POST | profile/update | update-profile | \App\Controllers\Auth\Profile::update | csrf session session | session |
| POST | profile/change-password | update-profile-password | \App\Controllers\Auth\Profile::changePassword | csrf session session | session |
| POST | profile/toggle-2fa | update-profile-2fa | \App\Controllers\Auth\Profile::toggle2FA | csrf session session | session |
| POST | profile/purge-remember-token | update-profile-purge-remember-token | \App\Controllers\Auth\Profile::purgeRememberToken | csrf session session | session |
| POST | register | » | \CodeIgniter\Shield\Controllers\RegisterController::registerAction | csrf auth-rates | |
| POST | login | » | \CodeIgniter\Shield\Controllers\LoginController::loginAction | csrf auth-rates | |
| POST | login/magic-link | » | \CodeIgniter\Shield\Controllers\MagicLinkController::loginAction | csrf auth-rates | |
| POST | auth/a/handle | auth-action-handle | \CodeIgniter\Shield\Controllers\ActionController::handle | csrf auth-rates | |
| POST | auth/a/verify | auth-action-verify | \CodeIgniter\Shield\Controllers\ActionController::verify | csrf auth-rates | |
+--------+------------------------------+-------------------------------------+--------------------------------------------------------------------+------------------------------------+-----------------------+
and check
Code: php spark filter:check GET /admin/users/
CodeIgniter v4.5.5 Command Line Tool - Server Time: 2024-12-02 11:48:42 UTC+00:00
+--------+---------------+---------------------------------------------------------+-----------------------------------------------------+
| Method | Route | Before Filters | After Filters |
+--------+---------------+---------------------------------------------------------+-----------------------------------------------------+
| GET | /admin/users/ | forcehttps pagecache csrf session permission permission | permission permission pagecache performance toolbar |
+--------+---------------+---------------------------------------------------------+-----------------------------------------------------+
-
WitER Junior Member
 
-
Posts: 10
Threads: 1
Joined: Apr 2021
Reputation:
0
12-11-2024, 07:48 AM
(This post was last modified: 12-11-2024, 08:13 AM by WitER.)
@ ozornick , i found why "permission:users.access" filter not work for child route "admin-users". This is because the parent group filter overwrites the filter arguments.
In my example - permission filter arguments for route group "/admin" rewrites arguments for route "/admin/users".
I just override " Codeigniter\Filters\Filters" class and it work.
PHP Code: <?php
declare(strict_types=1);
namespace App\Filters;
use CodeIgniter\Filters\Exceptions\FilterException; use CodeIgniter\Filters\FilterInterface; use CodeIgniter\Filters\Filters as BaseFilters; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface;
class Filters extends BaseFilters { /** * Ensures that specific filters are on and enabled for the current request. * * Filters can have "arguments". This is done by placing a colon immediately * after the filter name, followed by a comma-separated list of arguments that * are passed to the filter when executed. * * @params array<string> $names filter_name or filter_name:arguments like 'role:admin,manager' * * @return \App\Filters\Filters */ public function enableFilters(array $names, string $when = 'before'): self { foreach ($names as $filter) { $this->enableFilter($filter, $when); }
return $this; }
/** * Runs through all of the filters for the specified * uri and position. * * @param string $uri URI path relative to baseURL * @phpstan-param 'before'|'after' $position * * @return RequestInterface|ResponseInterface|string|null * * @throws FilterException */ public function run(string $uri, string $position = 'before') { $this->initialize(strtolower($uri));
if ($position === 'before') { return $this->runBefore($this->filtersClass[$position]); }
// After return $this->runAfter($this->filtersClass[$position]); }
private function enableFilter(string $name, string $when = 'before'): void { // Get arguments and clean name [$name, $arguments] = $this->getCleanName($name);
if (! array_key_exists($name, $this->arguments)) { $this->arguments[$name] = []; }
if ($arguments !== []) { $this->arguments[$name][] = $arguments; }
if ($this->arguments[$name] !== []) { $this->arguments[$name] = array_unique($this->arguments[$name] ?? [], SORT_REGULAR); } if ($this->arguments[$name] === []) { $this->arguments[$name] = null; }
if (class_exists($name)) { $this->config->aliases[$name] = $name; } elseif (! array_key_exists($name, $this->config->aliases)) { throw FilterException::forNoAlias($name); }
$classNames = (array) $this->config->aliases[$name];
foreach ($classNames as $className) { $this->argumentsClass[$className] = $this->arguments[$name] ?? null; }
if (! isset($this->filters[$when][$name])) { $this->filters[$when][] = $name; $this->filtersClass[$when] = array_merge($this->filtersClass[$when], $classNames); } }
/** * @return RequestInterface|ResponseInterface|string */ private function runBefore(array $filterClasses) { foreach ($filterClasses as $className) { $class = new $className();
if (! $class instanceof FilterInterface) { throw FilterException::forIncorrectInterface($class::class); }
if (array_key_exists($className, $this->argumentsClass) === true && $this->argumentsClass[$className] !== null && is_array($this->argumentsClass[$className][0]) ) { foreach ($this->argumentsClass[$className] as $classArgumentsRow) { $result = $class->before( $this->request, $classArgumentsRow );
if ($result instanceof RequestInterface) { $this->request = $result;
continue; }
// If the response object was sent back, // then send it and quit. if ($result instanceof ResponseInterface) { // short circuit - bypass any other filters return $result; }
// Ignore an empty result if (empty($result)) { continue; }
return $result; } } else {
$result = $class->before( $this->request, $this->argumentsClass[$className] ?? null );
if ($result instanceof RequestInterface) { $this->request = $result;
continue; }
// If the response object was sent back, // then send it and quit. if ($result instanceof ResponseInterface) { // short circuit - bypass any other filters return $result; }
// Ignore an empty result if (empty($result)) { continue; }
return $result; } }
return $this->request; }
private function runAfter(array $filterClasses): ResponseInterface { foreach ($filterClasses as $className) { $class = new $className();
if (! $class instanceof FilterInterface) { throw FilterException::forIncorrectInterface($class::class); }
if (array_key_exists($className, $this->argumentsClass) === true && $this->argumentsClass[$className] !== null && is_array($this->argumentsClass[$className][0]) ) { foreach ($this->argumentsClass[$className] as $classArgumentsRow) { $result = $class->after( $this->request, $this->response, $classArgumentsRow );
if ($result instanceof ResponseInterface) { $this->response = $result;
continue; } } } else { $result = $class->after( $this->request, $this->response, $this->argumentsClass[$className] ?? null );
if ($result instanceof ResponseInterface) { $this->response = $result;
continue; } } }
return $this->response; }
/** * Get clean name and arguments * * @param string $name filter_name or filter_name:arguments like 'role:admin,manager' * * @return array{0: string, 1: list<string>} [name, arguments] */ private function getCleanName(string $name): array { $arguments = [];
if (str_contains($name, ':')) { [$name, $arguments] = explode(':', $name);
$arguments = explode(',', $arguments); array_walk($arguments, static function (&$item): void { $item = trim($item); }); }
return [$name, $arguments]; }
}
and my Cofing\Services :
PHP Code: use App\Filters\Filters; use Config\Filters as FiltersConfig; use Config\Services as AppServices;
class Services extends BaseService {
/** * Filters allow you to run tasks before and/or after a controller * is executed. During before filters, the request can be modified, * and actions taken based on the request, while after filters can * act on or modify the response itself before it is sent to the client. * * @return Filters */ public static function filters(?FiltersConfig $config = null, bool $getShared = true) { if ($getShared) { return static::getSharedInstance('filters', $config); }
$config ??= config(FiltersConfig::class);
return new Filters($config, AppServices::get('request'), AppServices::get('response')); }
}
This is probably not the best solution, but at the moment I haven't come up with a better one
|