Symfony4로 로그인에 실패한 경우 로그에 출력

10831 단어 심포니PHP심포니4

소개



공식 문서의 보안How to Build a Login Form 를 보면서, 로그인 폼으로 로그인을 하는 샘플을 작성했습니다.

계속해서 로그인에 실패했을 경우에, 실패한 사람의 로그를 취득해 두고 싶습니다.

정책



How to Build a Login Form 로 작성한 경우, LoginFormAuthenticator.php 에 Logger 를 인젝션 해 출력하고 싶습니다.

이것을 하면 인증이라는 기능에 로깅이라는 다른 기능이 섞여 버리므로 잘 안되는 것 같습니다.

Symfony의 정석으로서는, 인증 종료 후에 Authentication Events 가 송신되므로, 이 이벤트를 기다리고 처리를 하는 것이 좋은 것 같습니다.

이벤트 리스너 작성



이벤트 리스너 클래스의 병아리 작성



Events and Event Listeners 을 읽으면서 이벤트 리스너를 만듭니다.

먼저 src 아래에 EventListener 디렉터리를 만듭니다.
해당 디렉토리 아래에 LoginLoggingListener 클래스를 만듭니다.



다음은 LoginLoggingListener 클래스의 골조입니다.EventSubscriberInterface를 상속합니다.

/src/EventListener/LoginLoggingListener.php
<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LoginLoggingListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        // TODO: Implement getSubscribedEvents() method.
    }
}

청취할 이벤트 등록



이벤트 구독 등록은 Creating an Event Listener 을 살펴보면 service.yaml 에 기재하는 방법과 Creating an Event Subscriber 를 구현해 나가는 방법이 있습니다.

이번에는 Event Subscriber를 구현합니다.

Authentication Events을 보면 로그인에 실패하면 security.authentication.failure의 이벤트가 발생하므로 이것을 후크하면 좋을 것 같습니다.



후크 함수로서 loggingLoginFailure 메소드를 등록합니다. 두 번째 10는 이 이벤트에 여러 후크 함수를 등록할 때 우선순위가 되는 번호입니다.

/src/EventListener/LoginLoggingListener.php
class LoginLoggingListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            AuthenticationEvents::AUTHENTICATION_FAILURE => [
                ['loggingLoginFailure', 10]
            ]
        ];
    }
}

이벤트 후크 함수 구현



훅 함수의 실태를 작성해 갑니다.
훅 함수에는 AuthenticationFailureEvent 가 건네집니다만, 원하는 정보는 들어가 있습니까?

일단 dd로 보자.

/src/EventListener/LoginLoggingListener.php
class LoginLoggingListener implements EventSubscriberInterface
{
~~~ 省略 ~~~

    public function loggingLoginFailure(AuthenticationFailureEvent $event):void
    {
   dd($event);
    }
}

이런 식으로, 로그인 폼에 입력된 정보의 메일 주소, 패스워드는 잡혔습니다!
그러나 중요한 클라이언트의 IP 등은 들어 있지 않습니다.



Controller처럼 Request
빙글빙글 보니 같은 일을 하고 싶은 사람이 계셨습니다.

Symfony - How to get username and IP address in authentication failure listener?

분명히 RequestStack를 주입하는 것이 좋습니다.
이 근처, 왜, RequestStack 가 좋은 것인지, 모르기 때문에, 누군가 자세한 분에게 가르쳐 주셨으면 합니다.

결국 LoggerInterface 도 주입하여 다음과 같이 되었습니다.

/src/EventListener/LoginLoggingListener.php
class LoginLoggingListener implements EventSubscriberInterface
{
    private $logger;
    private $requestStack;

    public function __construct(LoggerInterface $loginAuditLogger, RequestStack $requestStack)
    {
        $this->logger = $loginAuditLogger;
        $this->requestStack = $requestStack;
    }

    public static function getSubscribedEvents()
    {
        return [
            AuthenticationEvents::AUTHENTICATION_FAILURE => [
                ['LoggingLoginFailure', 10]
            ]
        ];
    }

    public function loggingLoginFailure(AuthenticationFailureEvent $event):void
    {
        $hCredentials = $event->getAuthenticationToken()->getCredentials();
        $this->logger->notice(sprintf('[Login Failure] email: %s, password: %s, ip: %s, ua: %s, referer: %s',
            $hCredentials['email'],
            $hCredentials['password'],
            $request->getClientIp(),
            $request->headers->get('user-agent'),
            $request->headers->get('referer')
        ));
    }
}

이번 취지와 다릅니다만, 로그는 독자 파일(login_audit-xxxx.log)에 출력하고 있습니다.



/var/log/login_audit-2019-12-24.log
[2019-12-24 16:43:15] login_audit.NOTICE: [Login Failure] email: [email protected], password: hogehoge, ip: 172.18.0.1, ua: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36, referer: https://localhost/login [] []

요약



Symfony에는 다양한 이벤트가 있기 때문에 그것을 사용하여 기능을 최소화하면 좋을 것 같네요.

이제 서비스라든지 번들이라든지, 이해하기 어려운 부분이 나왔기 때문에, 부담없이 일본어로 상담할 수 있는 멘터를 원하는 곳입니다.

좋은 웹페이지 즐겨찾기