🎻

[Symfony] FOSUserBundleを使わなくても15分でユーザーログインは実装できる

2020/03/25に公開

Symfonyでユーザー管理機能を実装するためのバンドルといえば FOSUserBundle が定番だと思います。

確かに、ユーザー管理に必要な最低限の機能を手早く実装できるという点では便利なバンドルなのですが、後々細かい拡張がしづらいという声も聞きます。

あと、個人的にSymfony2時代にしか使ったことがなかったので、Symfony4にちゃんと対応してるのか?という不安もあったのですが、リリースノート を見ると Added Symfony 4 compatibility. とか書かれているので特に心配は要らないっぽいです。

FOSUserBundleを使わずにユーザー管理機能を実装するとなると、色んな処理をゼロから書かないといけなくて面倒そうなイメージですが、実は MakerBundle を使えば意外と手軽に実装できます。

というわけで、今回はFOSUserbundleを使わずにユーザー管理を実装する手順を簡単に解説したいと思います✋

1. MakerBundleを使って一撃で User クラスを作る

https://symfony.com/doc/current/security.html

こちらの公式ドキュメントの焼き直しですが、MakerBundleを使えば、SecurityBundleの UserInterface を実装した、Doctrineエンティティとしての User クラスをコマンド一発で作れます。

$ bin/console make:user

 The name of the security user class (e.g. User) [User]:
 >

 Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
 >

 Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
 >

 Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).

 Does this app need to hash/check user passwords? (yes/no) [yes]:
 >

 created: src/Entity/User.php
 created: src/Repository/UserRepository.php
 updated: src/Entity/User.php
 updated: config/packages/security.yaml


  Success!


 Next Steps:
   - Review your new App\Entity\User class.
   - Use make:entity to add more fields to your User entity and then run make:migration.
   - Create a way to authenticate! See https://symfony.com/doc/current/security.html

make:user コマンドを叩いて、Enterを連打しただけです😇

これで、

  • src/Entity/User.php
    • SecurityBundleの UserInterface 実装済み
    • email プロパティがユーザー識別子
  • src/Repository/UserRepository.php

の2ファイルが作られ、以下のように config/packages/security.yaml にも必要な設定が追記されます。

security:
+   encoders:
+       App\Entity\User:
+           algorithm: auto
+
    providers:
-       in_memory: { memory: null }
+       # used to reload user from session & other features (e.g. switch_user)
+       app_user_provider:
+           entity:
+               class: App\Entity\User
+               property: email

あとはデータベースをマイグレーションすれば、 User クラスの作成は完了です!

$ bin/console doctrine:migrations:diff
$ bin/console doctrine:migrations:migrate

2. MakerBundleを使って一撃でログイン機能を作る

https://symfony.com/doc/current/security/form_login_setup.html

またしても公式ドキュメントの焼き直しですが、MakerBundleを使えば、ログイン画面とログイン処理(Authenticator)もコマンド一発で作れます。

$ bin/console make:auth

 What style of authentication do you want? [Empty authenticator]:
  [0] Empty authenticator
  [1] Login form authenticator
 > 1

 The class name of the authenticator to create (e.g. AppCustomAuthenticator):
 > LoginFormAuthenticator

 Choose a name for the controller class (e.g. SecurityController) [SecurityController]:
 >

 Do you want to generate a '/logout' URL? (yes/no) [yes]:
 >

 created: src/Security/LoginFormAuthenticator.php
 updated: config/packages/security.yaml
 created: src/Controller/SecurityController.php
 created: templates/security/login.html.twig


  Success!


 Next:
 - Customize your new authenticator.
 - Finish the redirect "TODO" in the App\Security\LoginFormAuthenticator::onAuthenticationSuccess() method.
 - Review & adapt the login template: templates/security/login.html.twig.

これで、

  • src/Controller/SecurityController.php/login/logout の2つのルートが実装済み)
  • src/Security/LoginFormAuthenticator.phpAbstractGuardAuthenticator を適切に実装済み)
  • templates/security/login.html.twig (ログイン画面のビュー)

の3ファイルが作られ、以下のように config/packages/security.yaml にも必要な設定が追記されます。

security:
    :
    :
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: lazy
+           guard:
+               authenticators:
+                   - App\Security\LoginFormAuthenticator
+           logout:
+               path: app_logout
+               # where to redirect after logout
+               # target: app_any_route

生成された雛形を修正

コマンド一発で生成された雛形は一箇所だけ修正が必要な内容になっています。

LoginFormAuthenticatoronAuthenticationSuccess メソッドの以下の部分です。

ログインに成功したあと、ターゲットパスがない場合にデフォルトでどのURLにリダイレクトさせるかを設定します。

以下の例では、 default_index というルート名のURLにリダイレクトさせています。

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
        return new RedirectResponse($targetPath);
    }

-   // For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
-   throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
+   return new RedirectResponse($this->urlGenerator->generate('default_index'));
}

3. アクセス制限を設定する

ここまででユーザーログインの機能は実装できているので、 config/packages/security.yaml で例えば以下のような感じでアクセス制限を設定すれば、「ログイン画面以外は ROLE_USER を持ったユーザーでログインしないと見られない」という状態が作れます。

security:
    :
    :
    access_control:
        - { path: ^/(login|logout)$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_USER }

まとめ

  • 現代においては、MakerBundleでユーザーログインに必要な実装がほぼコマンド一発で実装できる!
GitHubで編集を提案

Discussion