컨트롤러 필터
컨트롤러 필터를 사용하면 컨트롤러 실행 전이나 후에 작업을 수행할 수 있습니다. 이벤트와 달리 필터가 적용될 특정 URI 또는 경로를 선택할 수 있습니다. Before 필터는 요청을 수정할 수 있고, After 필터는 응답에 작용하여 응답을 수정할 수도 있으므로, 많은 유연성과 기능을 제공합니다.
필터로 수행할 수 있는 일반적인 작업 예시:
들어오는 요청에 대한 CSRF 보호 수행
사용자 역할에 따른 사이트 영역 제한
특정 엔드포인트에 대한 속도 제한 적용
서비스 점검(Down for Maintenance) 페이지 표시
자동 콘텐츠 협상 수행
그 외 여러 작업…
필터 생성하기
필터는 CodeIgniter\Filters\FilterInterface을 구현하는 간단한 클래스입니다. 여기에는 컨트롤러 전후에 각각 실행될 코드를 보유하는 before() 및 after()의 두 가지 메소드가 포함되어 있습니다. 클래스에는 두 메서드가 모두 포함되어야 하지만 필요하지 않은 경우 메서드를 비워 둘 수 있습니다. 뼈대 필터 클래스는 다음과 같습니다.
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class MyFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
// Do something here
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
// Do something here
}
}
Before 필터
요청 대체
모든 필터에서 $request 개체를 반환할 수 있으며 이 개체는 현재 요청을 대체하므로 컨트롤러가 실행될 때 여전히 존재하는 변경 사항을 만들 수 있습니다.
후속 필터 중지
또한 일련의 필터가 있는 경우 특정 필터 이후에 나중 필터의 실행을 중지할 수도 있습니다. 비어있지 않은 결과를 반환하면 쉽게 이 작업을 수행할 수 있습니다. 이전 필터가 빈 결과를 반환하는 경우 컨트롤러 작업이나 이후 필터는 계속 실행됩니다.
비어 있지 않은 결과 규칙의 예외는 Request 인스턴스입니다. before 필터에 반환하면 실행이 중지되지 않고 현재 $request 개체만 교체됩니다.
응답 반환
컨트롤러가 실행되기 전에 필터가 실행되기 때문에 때로는 컨트롤러에서 작업이 발생하지 않도록 중지하고 싶을 수도 있습니다.
이는 다음 예제와 같이 리다이렉트를 수행하는 데 일반적으로 사용됩니다:
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class MyFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
$auth = service('auth');
if (! $auth->isLoggedIn()) {
return redirect()->to(site_url('login'));
}
}
}
Response 인스턴스가 반환되면 응답이 클라이언트로 다시 전송되고 스크립트 실행이 중지됩니다. 이는 API에 대한 속도 제한을 구현하는 데 유용할 수 있습니다. 예를 보려면 Throttler을 참조하세요.
After 필터
이후 필터는 $response 개체만 반환할 수 있고 스크립트 실행을 중지할 수 없다는 점을 제외하면 이전 필터와 거의 동일합니다. 이를 통해 최종 출력을 수정하거나 최종 출력으로 간단히 작업을 수행할 수 있습니다. 이는 특정 보안 헤더가 올바른 방식으로 설정되었는지 확인하거나 최종 출력을 캐시하거나 나쁜 단어 필터로 최종 출력을 필터링하는 데 사용될 수 있습니다.
필터 구성
필터가 실행될 때 필터를 구성하는 방법에는 두 가지가 있습니다. 하나는 app/Config/Filters.php에서 수행되고, 다른 하나는 app/Config/Routes.php에서 수행됩니다.
정의된 경로에 필터를 지정하려면 app/Config/Routes.php를 사용하고 URI Routing을 참조하세요.
참고
필터를 적용하는 가장 안전한 방법은 disable auto-routing 및 set filters to routes에 적용하는 것입니다.
app/Config/Filters.php
app/Config/Filters.php 파일에는 필터가 실행되는 시기를 정확하게 구성할 수 있는 4가지 속성이 포함되어 있습니다.
경고
필터 설정에서 URI 끝에 항상 *을 추가하는 것이 좋습니다. 컨트롤러 메서드는 생각보다 다른 URL로 액세스할 수 있기 때문입니다. 예를 들어 Auto Routing (Legacy)이 활성화된 경우 Blog::index()이 있으면 blog, blog/index 및 blog/index/1 등을 사용하여 액세스할 수 있습니다.
$aliases
$aliases 배열은 실행할 필터인 하나 이상의 정규화된 클래스 이름과 간단한 이름을 연결하는 데 사용됩니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public array $aliases = [
'csrf' => \CodeIgniter\Filters\CSRF::class,
];
// ...
}
별칭은 필수이며, 나중에 전체 클래스 이름을 사용하려고 하면 시스템에서 오류를 발생시킵니다.
이러한 방식으로 정의하면 사용된 클래스를 쉽게 전환할 수 있습니다. 필터의 클래스만 변경하면 되므로 다른 인증 시스템으로 변경해야 할 때 좋습니다.
여러 필터를 하나의 별칭으로 결합하여 복잡한 필터 집합을 간단하게 적용할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public array $aliases = [
'api-prep' => [
\App\Filters\Negotiate::class,
\App\Filters\ApiAuth::class,
],
];
// ...
}
필요한 만큼 많은 별칭을 정의해야 합니다.
$required
Added in version 4.5.0.
두 번째 섹션에서는 필수 필터를 정의할 수 있습니다. 이들은 프레임워크에서 만든 모든 요청에 적용되는 특수 필터입니다. 아래에서 설명하는 다른 종류의 필터 전후에 적용됩니다.
참고
필수 필터는 항상 실행됩니다. 그러나 경로가 존재하지 않으면 Before 필터만 실행됩니다.
여기서 사용하는 필터의 수에 주의해야 합니다. 모든 요청에서 너무 많은 필터가 실행되면 성능에 영향을 미칠 수 있기 때문입니다. 그러나 기본적으로 설정된 필터는 프레임워크 기능을 제공합니다. 제거하면 해당 기능이 더 이상 작동하지 않습니다. 자세한 내용은 제공되는 필터를 참조하세요.
필터의 별칭을 before 또는 after 배열에 추가하여 필터를 지정할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $required = [
'before' => [
'forcehttps', // Force Global Secure Requests
'pagecache', // Web Page Caching
],
'after' => [
'pagecache', // Web Page Caching
'performance', // Performance Metrics
'toolbar', // Debug Toolbar
],
];
// ...
}
$globals
세 번째 섹션에서는 프레임워크에서 만든 모든 유효한 요청에 적용해야 하는 필터를 정의할 수 있습니다.
여기서 사용하는 필터의 수에 주의해야 합니다. 모든 요청에서 너무 많은 필터가 실행되면 성능에 영향을 미칠 수 있기 때문입니다.
필터의 별칭을 before 또는 after 배열에 추가하여 필터를 지정할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $globals = [
'before' => [
'csrf',
],
'after' => [],
];
// ...
}
몇 가지 URI 제외
거의 모든 요청에 필터를 적용하되 일부는 제외하고 싶을 때가 있습니다. 일반적인 예는 타사 웹사이트의 요청이 특정 URI에 도달하도록 허용하면서 나머지는 보호된 상태로 유지하기 위해 CSRF 보호 필터에서 몇 가지 URI를 제외해야 할 때입니다.
이를 수행하려면 except 키와 별칭과 함께 값으로 일치하는 URI 경로(BaseURL에 상대적)를 포함하는 배열을 추가하세요:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $globals = [
'before' => [
'csrf' => ['except' => 'api/*'],
],
'after' => [],
];
// ...
}
경고
v4.4.7 이전에는 버그로 인해 필터에서 처리한 URI 경로가 URL 디코딩되지 않았습니다. 즉, 라우팅에 지정된 URI 경로와 필터에 지정된 URI 경로가 다를 수 있습니다. 자세한 내용은 컨트롤러 필터의 경로를 참조하세요.
필터 설정에서 URI 경로(BaseURL에 상대적)를 사용할 수 있는 모든 곳에서 정규 표현식을 사용하거나 위의 예제처럼 별표(*)를 사용하여 그 이후의 모든 문자와 일치하는 와일드카드를 사용할 수 있습니다. 이 예제에서는 api/로 시작하는 모든 URI 경로가 CSRF 보호에서 제외되지만, 사이트의 양식은 모두 보호됩니다.
여러 URI 경로를 지정해야 하는 경우 URI 경로 패턴 배열을 사용할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $globals = [
'before' => [
'csrf' => ['except' => ['foo/*', 'bar/*']],
],
'after' => [],
];
// ...
}
$methods
경고
$methods 필터를 사용하려면 자동 라우팅(레거시) 비활성화해야 합니다. Auto Routing (Legacy)는 모든 HTTP 메서드가 컨트롤러에 액세스할 수 있기 때문입니다. 예상하지 못한 메서드로 컨트롤러에 액세스하면 필터를 우회할 수 있습니다.
POST, GET, PUT 등 특정 HTTP 메서드의 모든 요청에 필터를 적용할 수 있습니다. 값은 실행할 필터의 배열입니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $methods = [
'POST' => ['invalidchars', 'csrf'],
'GET' => ['csrf'],
];
// ...
}
참고
$globals 또는 $filters 속성과 달리 이들은 Before 필터로만 실행됩니다.
표준 HTTP 메서드 외에도 특수한 경우가 하나 있습니다: CLI. CLI 메서드는 명령줄에서 실행된 모든 요청에 적용됩니다.
참고
v4.5.0 이전에는 버그로 인해 HTTP 메서드 이름을 소문자로 지정해야 했습니다.
$filters
이 속성은 필터 별칭의 배열입니다. 각 별칭에 대해 필터가 적용되어야 하는 URI 경로(BaseURL에 상대적) 패턴 목록을 포함하는 before 및 after 배열을 지정할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public array $filters = [
'foo' => ['before' => ['admin/*'], 'after' => ['users/*']],
'bar' => ['before' => ['api/*', 'admin/*']],
];
// ...
}
경고
v4.4.7 이전에는 버그로 인해 필터에서 처리한 URI 경로가 URL 디코딩되지 않았습니다. 즉, 라우팅에 지정된 URI 경로와 필터에 지정된 URI 경로가 다를 수 있습니다. 자세한 내용은 컨트롤러 필터의 경로를 참조하세요.
필터 인수
Added in version 4.4.0.
$filters를 구성할 때 필터에 추가 인수를 전달할 수 있습니다:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
// ...
public $filters = [
'group:admin,superadmin' => ['before' => ['admin/*']],
'permission:users.manage' => ['before' => ['admin/users/*']],
];
// ...
}
이 예제에서 URI가 admin/*와 일치하면 배열 ['admin', 'superadmin']이 $arguments의 group 필터의 before() 메서드에 전달됩니다. URI가 admin/users/*와 일치하면 배열 ['users.manage']이 $arguments의 permission 필터의 before() 메서드에 전달됩니다.
참고
v4.6.0 이전에는 동일한 필터를 다른 인수로 여러 번 실행할 수 없었습니다.
필터 실행 순서
중요
v4.5.0부터 필터가 실행되는 순서가 변경되었습니다. 이전 버전과 동일한 실행 순서를 유지하려면 true을 Config\Feature::$oldFilterOrder로 설정해야 합니다.
필터는 다음 순서로 실행됩니다:
Before 필터: required → globals → methods → filters → route
After 필터: route → filters → globals → required
참고
required 필터는 v4.5.0부터 사용할 수 있습니다.
참고
v4.5.0 이전에는 경로에 지정된 필터(app/Config/Routes.php)가 app/Config/Filters.php에 지정된 필터보다 먼저 실행되었습니다. 그리고 Route 필터와 Filters 필터의 After 필터 실행 순서가 역순이 아니었습니다. 자세한 내용은 Upgrading Guide를 참조하세요.
필터 확인
CodeIgniter는 경로의 필터를 확인하기 위해 다음 명령을 가지고 있습니다.
filter:check
Added in version 4.3.0.
예를 들어 GET 메서드를 사용하여 경로 /의 필터를 확인합니다:
php spark filter:check get /
출력은 다음과 같습니다:
+--------+-------+----------------------+-------------------------------+
| Method | Route | Before Filters | After Filters |
+--------+-------+----------------------+-------------------------------+
| GET | / | forcehttps pagecache | pagecache performance toolbar |
+--------+-------+----------------------+-------------------------------+
Before Filter Classes:
CodeIgniter\Filters\ForceHTTPS → CodeIgniter\Filters\PageCache
After Filter Classes:
CodeIgniter\Filters\PageCache → CodeIgniter\Filters\PerformanceMetrics → CodeIgniter\Filters\DebugToolbar
참고
v4.6.0 이후, 필터 인수가 출력 테이블에 표시되었습니다. 또한 실제 필터 클래스 이름이 끝에 표시되었습니다.
spark routes 명령으로 경로 및 필터를 볼 수 있지만, 경로에 대해 정규 표현식을 사용할 때는 정확한 필터를 표시하지 않을 수 있습니다. 자세한 내용은 URI Routing를 참조하세요.
제공되는 필터
CodeIgniter4와 함께 번들된 필터는 다음과 같습니다:
cors=> 교차 출처 리소스 공유 (CORS)csrf=> CSRFtoolbar=> DebugToolbarhoneypot=> Honeypotinvalidchars=> InvalidCharssecureheaders=> SecureHeadersforcehttps=> ForceHTTPSpagecache=> PageCacheperformance=> 성능 메트릭
참고
필터는 구성 파일에 정의된 순서대로 실행됩니다. 그러나 활성화된 경우 DebugToolbar는 항상 마지막에 실행됩니다. 이는 다른 필터에서 발생하는 모든 것을 캡처할 수 있기 때문입니다.
ForceHTTPS
Added in version 4.5.0.
이 필터는 “Force Global Secure Requests” 기능을 제공합니다.
Config\App:$forceGlobalSecureRequests을 true로 설정하면 이 애플리케이션에 대한 모든 요청이 보안 연결(HTTPS)을 통해 이루어지게 됩니다. 들어오는 요청이 안전하지 않은 경우 사용자는 페이지의 보안 버전으로 리디렉션되고 HSTS(HTTP Strict Transport Security) 헤더가 설정됩니다.
성능 메트릭
Added in version 4.5.0.
이 필터는 성능 메트릭을 위한 의사 변수를 제공합니다.
CodeIgniter가 시작되는 순간부터 최종 출력이 브라우저로 전송되기 바로 전까지의 총 경과 시간을 표시하려면 보기 중 하나에 이 의사 변수를 넣으면 됩니다:
{elapsed_time}
보기 파일에서 메모리 사용량을 표시하려면 이 의사 변수를 사용하세요:
{memory_usage}
이 기능이 필요하지 않으면 $required['after']에서 'performance'를 제거하세요.
InvalidChars
이 필터는 사용자 입력 데이터($_GET, $_POST, $_COOKIE, php://input)가 다음 문자를 포함하지 않도록 방지합니다:
잘못된 UTF-8 문자
줄 바꿈 및 탭 코드를 제외한 제어 문자
SecureHeaders
이 필터는 애플리케이션의 보안을 강화하는 데 사용할 수 있는 HTTP 응답 헤더를 추가합니다.
헤더를 사용자 정의하려면 CodeIgniter\Filters\SecureHeaders을 확장하고 $headers 속성을 재정의하세요. 그리고 app/Config/Filters.php에서 $aliases 속성을 변경하세요.
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public array $aliases = [
// ...
'secureheaders' => \App\Filters\SecureHeaders::class,
];
// ...
}
보안 헤더에 대해 알고 싶으면 OWASP Secure Headers Project를 참조하세요.