드라이버 기반 서비스를 통해 Laravel을 확장하는 방법

안녕하세요, Valerio, Inspector의 소프트웨어 엔지니어 겸 수석 기술관입니다.
본문에서 공식 문서에 언급되지 않은'드라이브 매니저'라는 Laravel 내부 기능에 대해 논의하겠습니다.이것은 당신이 응용 프로그램을 설계하고 개발하는 방식을 완전히 바꾸고 관건적인 체계 구조의 병목을 해결하며, 결합, 독립, 재사용 가능한 구성 요소를 둘러싸고 대형 시스템을 구축할 수 있도록 합니다.
프레임워크의 창설자는 이를 추상적인 공공 서비스로 광범위하게 사용해서 사용자가 이러한 서비스의 다양한 유형의 기술과 상호작용을 할 수 있도록 합니다.
로그(파일, 시스템 로그, 서면 기록, slack 등에 로그인할 수 있음), 캐시(데이터를 파일,redis,memecached 등에 캐시할 수 있음), 세션(파일, 데이터베이스 등 PHP 세션을 저장할 수 있음)과 기타 일반적인 구성 요소를 고려해 보세요.

Laravel 프레임워크에서 드라이버 관리자의 작동 방식
위에서 설명한 바와 같이 Laravel은 드라이버 시스템을 사용하여 구축된 많은 구성 요소를 제공합니다.
\Log::debug('message');

\Cache::get('key');

\Session::get('key');

이러한 외관을 사용할 때, Laravel은 어떤 실현 (드라이버) 을 사용해야 하는지 어떻게 알 수 있습니까?
모든 서비스는 자신의 설정 파일을 가지고 있다.캐시 서비스의 경우 config/Cache에 있습니다.php 프로필:
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
| Supported: "apc", "array", "database", "file",
|            "memcached", "redis", "dynamodb"
|
*/

'default' => env('CACHE_DRIVER', 'file'),
기본 드라이버 값을 파일에서 데이터베이스로 변경하면 Laravel은 파일이 아닌 데이터베이스를 사용하여 캐시를 저장하고 검색합니다.
필요한 경우 런타임 시 한 드라이버에서 다른 드라이버로 전환할 수도 있습니다.
\Cache::driver('file')->put('key', 'value');
분명히 설정 파일에 드라이버를 정확하게 설정해야만 작동할 수 있습니다.
다음은 Facade 클래스가 액세스할 수 있도록 자체 드라이버 기반 구성 요소를 개발하는 방법과 IoC 컨테이너에 바인딩하는 방법을 보여 드리겠습니다.

드라이버 기반 서비스는 언제 개발됩니까?
여러 기술이 같은 실용 프로그램을 제공할 수 있을 때 드라이버 기반 서비스는 올바른 선택이다.
이러한 드라이버가 있기 때문에, 당신은 모든 하부 기술을 구체적으로 개발하고, 그것들 사이를 전환하며, 간단한 설정 파라미터를 변경할 수 있으며, 심지어는 환경 변수를 더욱 간단하게 변경할 수 있다.
이 정책은 개발 환경에서 file을 캐시로 사용하고 생산 환경에서 Redis를 사용하며 cache DRIVER 환경 변수에 대해 다른 값을 설정하기만 하면 됩니다.
# DEV environment - Set file as default cache storage
CACHE_DRIVER=file

# PROD environment - Set Redis as default cache storage
CACHE_DRIVER=redis
로그, 캐시, 세션 서비스가 완벽한 예이다.로그, 캐시, 세션은 어떤 베이스 기술을 사용하든지 기능적인 요구입니다.
모든 개발자는 데이터베이스에서 임시 정보를 캐시하여 성능을 향상시켜야 하지만, 캐시 서비스는 Redis, Memcached, File 등 다양한 기술로 제공할 수 있다.
어떤 기술을 사용하든 캐시에 값을 저장해야 합니다.
\Cache::put('key', 'value');
캐시에서 값을 검색합니다.
$value = \Cache::get('key');
이러한 메커니즘이 어떻게 작동하는지 더욱 잘 이해하기 위해 내부 방화벽 서비스를 구축하는 실제 사례를 보여 드리겠습니다.
위에서 설명한 정의에 따르면 방화벽은 여러 가지 유형의 시스템으로 Cloudflare,fail2ban,Google Cloud Armor,AWS가 호스팅하는 방화벽 등을 해결할 수 있는 기능적 요구사항입니다.

방화벽 구성 요소 구현
우선, 우리는 모든 드라이버가 반드시 실현해야 하는 방화벽의 유니버설 인터페이스를 정의해야 한다.
방화벽의 용도로 볼 때, 우리는 일반적으로 IP 주소가 우리의 인프라 시설에 도착하는 것을 거부하거나, 그들이 인프라 시설에 데이터를 보내는 것을 허락할 수 있어야 한다.
방화벽 인터페이스는 다음과 같습니다.
namespace App\Firewall\Contracts;


interface FirewallInterface
{
    /**
     * Allow web traffic from the give ip addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function allow(array $ips);

    /**
     * Deny web traffic from the given IP addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function deny(array $ips);
}
모든 드라이버는 이 인터페이스를 실현해야 하기 때문에 '드라이버 관리자' 를 개발할 때, 우리는 프로그램이 계속 작동하도록 한 드라이버에서 다른 드라이버로 이동할 수 있다.
첫 번째 프레젠테이션은 로그 파일에 지정한 IP 주소의 목록을 쓰는 간단한 기록기일 수 있습니다."LogFirewallDriver"라고 합니다.
namespace App\Firewall\Drivers;


use App\Firewall\Contracts\FirewallInterface;
use Psr\Log\LoggerInterface;

class LogFirewallDriver implements FirewallInterface
{
    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * LogFirewallDriver constructor.
     *
     * @param LoggerInterface|null $logger
     */
    public function __construct(LoggerInterface $logger = null)
    {
        $this->logger = $logger;
    }

    /**
     * Allow web traffic from the give ip addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function allow(array $ips)
    {
        if ($this->logger) {
            $this->logger->debug('Allow traffic from: ' . implode(', ', $ips));
        }
    }

    /**
     * Deny web traffic from the given IP addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function deny(array $ips)
    {
        if ($this->logger) {
            $this->logger->debug('Deny traffic from: ' . implode(', ', $ips));
        }
    }
}

Manager 클래스 구현 방법
드라이버 기반 구성 요소를 구축할 때 이를 관리하는 방법이 필요합니다.우리는 몇 개의 미리 정의된 드라이버를 만들 수 있기를 희망하며, 심지어는 응용 프로그램의 생명 주기의 잠시 후에 그것들을 만들 수 있기를 희망한다.
본고의 첫머리에서 보듯이, 우리는 실행할 때 특정 드라이버의 실례를 요청하고, 드라이버를 지정하지 않은 상황에서 프록시 호출을 할 수 있도록 예비 드라이버를 원한다.
이것은 \Illuminate\Support\Manager반의 일이다.
Laravel은 지원 이름 공간 (\Illuminate\Support\Manager 에서 이 추상 관리자 클래스를 제공합니다. 이것은 내장 기능을 포함하여 드라이버 시스템을 관리합니다.
우선, 이 클래스를 확장하고, 예를 들어 createLogDriver() 방법을 정의해야 합니다.
namespace App\Firewall;


use Illuminate\Support\Manager;

class FirewallManager extends Manager
{
    /**
     * Get the default driver name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return config('firewall.default') ?? 'log';
    }

    /**
     * Get an instance of the log driver.
     *
     * @return LogFirewallDriver
     */
    public function createLogDriver(): FirewallInterface
    {
        return new LogFirewall(
            $this->container['log']->channel(config('firewall.drivers.log.channel'))
        );
    }
}
드라이버 생성 방법은 다음과 같은 형식create[Drivername]Driver을 따라야 한다. 그 중에서 드라이브name은 연구를 거친 드라이버 이름이다.
관리자 클래스에서 정의된 드라이버 생성 방법은 드라이버 인터페이스의 실례를 되돌려야 합니다.
기본 관리자 클래스는 드라이버를 만들고 관리하는 데 도움을 줄 수 있는 몇 가지 내장 논리를 정의합니다.이것은 추상적인 클래스이고 getDefaultDriver() 방법을 설명하기 때문에 기본 드라이버 이름을 되돌려 주는 방법을 실현해야 합니다.

FirewallManager 구성 요소를 IoC 컨테이너에 바인딩하는 방법
응용 프로그램의 방화벽 구성 요소에 액세스하려면 FirewallManager 클래스를 Laravel의 서비스 컨테이너에 등록해야 합니다.AppServiceProvider에 다음 코드를 추가합니다.
namespace App\Providers;


use App\Firewall\FirewallManager;

class AppServiceProvider extend ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('firewall', function ($app) {
            return new FirewallManager($app);
        });
    }
}
또한 귀속 서비스에 쉽게 액세스할 수 있도록 방화벽 도어를 만들었습니다.
namespace App\Firewall\Facades;


/**
 * @method static FirewallInterface getDefaultDriver()
 * @method static FirewallInterface driver(string $name)
 * @method static FirewallManager extend(string $driver, \Closure $callback)
 * @method static mixed allow(array $ips)
 * @method static mixed deny(array $ips)
 */
class Firewall extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     *
     * @throws \RuntimeException
     */
    protected static function getFacadeAccessor()
    {
        return 'firewall';
    }
}
마지막으로 config\firewall.php 구성 파일을 생성하여 각 드라이버의 특정 구성 옵션을 저장합니다.
return [
    /*
    |--------------------------------------------------------------------------
    | Default Firewall Driver
    |--------------------------------------------------------------------------
    |
    | This option defines the default firewall driver that gets used when try to
    | allow or deny traffic for some IPs addresses. The name specified in this option should match
    | one of the driver defined in the "drivers" configuration array.
    |
    */

    'default' => env('FIREWALL_DRIVER', 'log'),

    /*
    |--------------------------------------------------------------------------
    | Configuration options for each driver
    |--------------------------------------------------------------------------
    |
    | Here you may configure the firewall drivers for Inspector. Out of
    | the box, Inspector is able to allow and deny traffic using the
    | firewalls below.
    |
    */

    'drivers' => [
        'log' => [
            'channel' => 'daily'
        ]
    ]
];

방화벽 구성 요소 사용 방법
방화벽으로 facade를 등록하고 프로필을 설정하면 Firewall Manager의 실례를 쉽게 얻을 수 있고 드라이버 기능에 접근할 수 있습니다.
\Firewall::deny(['127.0.0.1', '127.0.0.2']);
기본적으로 로그 드라이버가 사용되므로 로그 항목을 보아야 합니다.
[2021-08-19 14:37:55] local.DEBUG: Deny traffic from: 127.0.0.1, 127.0.0.2

새 드라이버 추가
Firewall Manager가 있으면 우리는 현재 새로운 방화벽을 쉽게 개발하여 다른 시스템과 상호작용을 할 수 있다.예를 들어, 프로그램의 코드에 접근하지 않고 클라우드 플레이어 방화벽과 상호작용을 할 수 있도록 '클라우드 플레이어' 드라이버를 구현하고 추가하는 방법을 보여 드리겠습니다.LogFireallDriver의 실현과 같이 우리는 유니버설 방화벽 인터페이스를 실현하기 위해 CloudflareFirewallDriver를 만들어야 한다.
namespace App\Firewall\Drivers;


use App\Firewall\Contracts\FirewallInterface;

class CloudflareFirewallDriver implements FirewallInterface
{
    /**
     * Http client to interact with Cloudflare API.
     *
     * @var \Guzzle\Client $client
     */
    protected $client;

    /**
     * CloudflareFirewallDriver constructor.
     *
     * @param string $zoneId
     */
    public function __construct(string $zoneId)
    {
        $this->client = new \Guzzle\Client('https://api.cloudflare.com/client/v4/zones/' . $zoneId)
    }

    /**
     * Allow web traffic from the given ip addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function allow(array $ips)
    {
        // Call Cloudflare API to allow traffic from the given IP addresses.
        $this->client->put('filters', ...);
    }

    /**
     * Deny web traffic from the given IP addresses.
     *
     * @param array $ips
     * @return mixed
     */
    public function deny(array $ips)
    {
        // Call Cloudflare API to deny traffic from the given IP addresses.
        $this->client->put('filters', ...);
    }
}
constructor 방법에서 보듯이 Cloudflare API 단점을 올바르게 구축하려면 "zoneId"를 제공해야 합니다.구성/방화벽에 새 항목을 추가할 수 있습니다.이 새 드라이버의 php 구성 파일:
return [
    /*
    |--------------------------------------------------------------------------
    | Default Firewall Driver
    |--------------------------------------------------------------------------
    |
    | This option defines the default firewall driver that gets used when try to
    | allow or deny traffic for some IPs addresses. The name specified in this option should match
    | one of the driver defined in the "drivers" configuration array.
    |
    */

    'default' => env('FIREWALL_DRIVER', 'log'),

    /*
    |--------------------------------------------------------------------------
    | Configuration options for each driver
    |--------------------------------------------------------------------------
    |
    | Here you may configure the firewall drivers for Inspector. Out of
    | the box, Inspector is able to allow and deny traffic using the
    | firewalls below.
    |
    */

    'drivers' => [
        'log' => [
            'channel' => 'daily'
        ],

        'cloudflare' => [
            'zone' => 'xxx'
        ]
    ]
];
우리는 또한 FirewallManager에게 이 새 기사를 알려야 한다.새로운 createCloudflareDriver() 방법을 추가하여 생성 논리를 정의할 수 있습니다.
namespace App\Firewall;


use Illuminate\Support\Manager;

class FirewallManager extends Manager
{
    /**
     * Get the default driver name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return config('firewall.default') ?? 'log';
    }

    /**
     * Get an instance of the log driver.
     *
     * @return LogFirewallDriver
     */
    public function createLogDriver(): FirewallInterface
    {
        return new LogFirewall(
            $this->container['log']->channel(config('firewall.drivers.log.channel'))
        );
    }


    /**
     * Get an instance of the Cloudlfare driver.
     *
     * @return CloudflareFirewallDriver
     */
    public function createCloudflareDriver(): FirewallInterface
    {
        return new CloudflareFirewallDriver(
            config('firewall.drivers.cloudflare.zone'))
        );
    }
}
이제 새 드라이버로 자유롭게 전환하거나 환경 파일에서 기본 드라이버로 구성할 수 있습니다.
\Firewall::driver('cloudflare')->deny(['127.0.0.1', '127.0.0.2']);

결론
Laravel을 사용하면 Manager 클래스를 사용하여 드라이버 기반 구성 요소를 쉽게 생성할 수 있습니다.나는 이 틀을 탐색함으로써 이 점을 알게 되었다. 나는 너도 이 습관을 길러야 한다고 건의한다. 왜냐하면 그것은 항상 새로운 학습 기회를 제공하고 너의 발전 기능을 향상시킬 수 있기 때문이다.

새로 온 감독?
소프트웨어 개발자를 위한 모니터링 환경을 구축하여 많은 개발자들이 처리하지 않으려는 서버나 인프라 시설의 설정을 피한다.
Inspector 덕분에 서버 레벨에 물건을 설치할 필요도 없고 클라우드 인프라에서 복잡한 설정을 할 필요도 없습니다.
Inspector는 경량급 소프트웨어 라이브러리를 사용하여 다른 의존항과 같이 응용 프로그램에 설치할 수 있습니다.Laravel이면 저희 공식Laravel package을 사용할 수 있습니다.개발자들은 항상 서버 단계에서 소프트웨어를 설치하고 설정하는 것을 좋아하지 않는다. 왜냐하면 이러한 설치는 소프트웨어 개발의 생명 주기를 초과하고 심지어 외부 팀에서 관리하기 때문이다.
자세한 내용은 웹 사이트를 참조하십시오.https://inspector.dev/laravel/

좋은 웹페이지 즐겨찾기