symfonyでログインフォームの実装(5.4以降)

以前はmake:authコマンドにより実装できたようだが、6以降では使えないようなのでドキュメントに則って作成する。

Form Login

ほとんどの Web サイトには、ユーザーが識別子 (電子メール アドレスやユーザー名など) とパスワードを使用して認証するログイン フォームがあります。この機能は、フォーム ログイン認証システムによって提供されます。

まず、ログイン フォームのコントローラーを作成します。

php bin/console make:controller Login

 created: src/Controller/LoginController.php
 created: templates/login/index.html.twig
// src/Controller/LoginController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class LoginController extends AbstractController
{
    #[Route('/login', name: 'app_login')]
    public function index(): Response
    {
        return $this->render('login/index.html.twig', [
            'controller_name' => 'LoginController',
        ]);
    }
}

次に、[form_login] 設定を使用してフォーム ログイン認証を有効にします。

# config/packages/security.yaml
security:
    # ...

    firewalls:
        main:
            # ...
            form_login:
                # "app_login" is the name of the route created previously
                login_path: app_login
                check_path: app_login
[login_path] と [check_path] は URL とルート名をサポートします (ただし、ワイルドカードを必須にすることはできません。たとえば、[/login/{foo}] の場合、[foo] にはデフォルト値がありません)。

有効にすると、認証されていない訪問者がセキュアな場所にアクセスしようとすると、セキュリティ システムによって [login_path] にリダイレクトされます (この動作は、認証エントリ ポイントを使用してカスタマイズできます)。

ログイン コントローラを編集して、ログイン フォームをレンダリングします。

// ...
+ use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

  class LoginController extends AbstractController
  {
      #[Route('/login', name: 'app_login')]
-     public function index(): Response
+     public function index(AuthenticationUtils $authenticationUtils): Response
      {
+         // get the login error if there is one
+         $error = $authenticationUtils->getLastAuthenticationError();
+
+         // last username entered by the user
+         $lastUsername = $authenticationUtils->getLastUsername();
+
          return $this->render('login/index.html.twig', [
-             'controller_name' => 'LoginController',
+             'last_username' => $lastUsername,
+             'error'         => $error,
          ]);
      }
  }

このコントローラーをややこしくしないでください。その仕事は、フォームをレンダリングすることだけです。[form_login] オーセンティケーターは、フォームの送信を自動的に処理します。ユーザーが無効な電子メールまたはパスワードを送信した場合、そのオーセンティケーターはエラーを保存し、このコントローラーにリダイレクトして戻します。そこでエラーを読み取り ([AuthenticationUtils] を使用)、ユーザーに表示できるようにします。

最後に、テンプレートを作成または更新します。

{# templates/login/index.html.twig #}
{% extends 'base.html.twig' %}

{# ... #}

{% block body %}
    {% if error %}
        <div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
    {% endif %}

    <form action="{{ path('app_login') }}" method="post">
        <label for="username">Email:</label>
        <input type="text" id="username" name="_username" value="{{ last_username }}">

        <label for="password">Password:</label>
        <input type="password" id="password" name="_password">

        {# If you want to control the URL the user is redirected to on success
        <input type="hidden" name="_target_path" value="/account"> #}

        <button type="submit">login</button>
    </form>
{% endblock %}
テンプレートに渡される [error] 変数は、AuthenticationException のインスタンスです。認証の失敗に関する機密情報が含まれている場合があります。 [error.message] は使用しないでください。例に示すように、代わりに [messageKey] プロパティを使用してください。このメッセージは常に安全に表示できます。

フォームは何にでも似ていますが、通常はいくつかの規則に従います。

  • [<form>] 要素は [app_login] ルートに [POST] リクエストを送信します。これは、[security.yaml] の [form_login] キーの下に [check_path] として設定したものであるためです。
  • ユーザー名 (または電子メールなどのユーザーの「識別子」) フィールドには [_username] という名前があり、パスワード フィールドには [_password] という名前があります。
実際、これらはすべて [form_login] キーの下で設定できます。詳細については、セキュリティ構成リファレンス (SecurityBundle)を参照してください。
このログイン フォームは現在、CSRF 攻撃から保護されていません。ログインフォームを保護する方法については、セキュリティをお読みください。

プロセス全体を確認するには:

  1. ユーザーが保護されているリソース ([/admin] など) にアクセスしようとしています。
  2. ファイアウォールは、ユーザーをログイン フォーム ([/login]) にリダイレクトすることにより、認証プロセスを開始します。
  3. [/login] ページは、この例で作成されたルートとコントローラーを介してログイン フォームをレンダリングします。
  4. ユーザーはログイン フォームを [/login] に送信します。
  5. セキュリティ システム (つまり、[form_login] オーセンティケーター) は、要求をインターセプトし、ユーザーが送信した資格情報を確認し、正しい場合はユーザーを認証し、正しくない場合はユーザーをログイン フォームに送り返します。

ログイン試行の成功または失敗に対する応答をカスタマイズできます。フォーム ログイン認証応答のカスタマイズを参照してください。