管理者のバックエンドをセキュアにする
管理者のバックエンドのインターフェースは、信頼された人からのみアクセス可能であるべきです。Symfony のセキュリティコンポーネントを使用して、Web サイトをセキュアにします。
User エンティティを定義する
参加者が Web サイトに自分のアカウントを作成することはできないですが、ここでは管理者のために正しく機能する認証システムを作成しましょう。そのために、Webサイトの管理者のユーザーを一つだけ用意します。
最初のステップは、 User
エンティティを定義することです。混乱を避けるためにここでは Admin
を使います。
Symfony のセキュリティ認証システムで Admin
エンティティを使用するためには、password
プロパティなどの要件が必要になります。
make:entity
ではなく、専用の make:user
コマンドを使用して Admin
エンティティを作成してください:
1
$ symfony console make:user Admin
インタラクティブな質問に次のように答えてください: 管理者を Doctrine に格納したいので (yes
)、 管理者のユニークな表示名を username
、そして各ユーザーがパスワードを1つ持つことに(yes
)と。
生成されたクラスには、getRole()
, eraseCredentials()
メソッドの他にも Symfony の認証システムで必要なものが入っています。
Admin
ユーザーにさらにプロパティを追加したければ、 make:entity
を使用してください。
EasyAdmin のように __toString()
メソッドを追加しましょう:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
--- a/src/Entity/Admin.php
+++ b/src/Entity/Admin.php
@@ -54,6 +54,11 @@ class Admin implements UserInterface, PasswordAuthenticatedUserInterface
return (string) $this->username;
}
+ public function __toString(): string
+ {
+ return $this->username;
+ }
+
/**
* @see UserInterface
*/
Admin
エンティティを生成するだけでなく、このコマンドは、認証システムとエンティティのワイヤリングのためのセキュリティ設定を更新します:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -1,7 +1,15 @@
security:
+ password_hashers:
+ App\Entity\Admin:
+ algorithm: auto
+
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
- in_memory: { memory: null }
+ # used to reload user from session & other features (e.g. switch_user)
+ app_user_provider:
+ entity:
+ class: App\Entity\Admin
+ property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
Symfony にパスワードをハッシュ化するのに一番有効なアルゴリズムを選択させましょう(これは時が経つと変更されていくものです)。
マイグレーションを生成して、データベースをmigrateします:
1 2
$ symfony console make:migration
$ symfony console doctrine:migrations:migrate -n
管理者ユーザーのパスワードを生成する
管理者のアカウントを作成するのに専用のシステムを開発することはないです。ここでは1つの管理者しか用意しませんから。ログインするには admin
とハッシュ化されたパスワードが必要になります。
App\Entity\Admin
を選び、好きなパスワードを選択して、次のコマンドを実行しパスワードをハッシュ化してください:
1
$ symfony console security:hash-password
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Symfony Password Hash Utility
=============================
Type in your password to be hashed:
>
------------------ ---------------------------------------------------------------------------------------------------
Key Value
------------------ ---------------------------------------------------------------------------------------------------
Hasher used Symfony\Component\PasswordHasher\Hasher\MigratingPasswordHasher
Password hash $argon2id$v=19$m=65536,t=4,p=1$BQG+jovPcunctc30xG5PxQ$TiGbx451NKdo+g9vLtfkMy4KjASKSOcnNxjij4gTX1s
------------------ ---------------------------------------------------------------------------------------------------
! [NOTE] Self-salting hasher used: the hasher generated its own built-in salt.
[OK] Password hashing succeeded
管理者を作成する
次の SQL で管理者ユーザーを追加してください:
1 2 3
$ symfony run psql -c "INSERT INTO admin (id, username, roles, password) \
VALUES (nextval('admin_id_seq'), 'admin', '[\"ROLE_ADMIN\"]', \
'\$argon2id\$v=19\$m=65536,t=4,p=1\$BQG+jovPcunctc30xG5PxQ\$TiGbx451NKdo+g9vLtfkMy4KjASKSOcnNxjij4gTX1s')"
パスワードの値の $
符号は全てエスケープしましょう。
セキュリティ認証を設定する
管理者ユーザーができましたので、管理者のバックエンドをセキュアにすることができます。 Symfony は複数の認証の方法をサポートしていますが、ここでは、昔から人気のある フォーム認証システム を使いましょう。
make:auth
コマンドを実行しセキュリティ設定を更新し、ログインテンプレートを作成し、 認証システム を作成しましょう:
1
$ symfony console make:auth
1
を選択し、ログインフォーム認証システムを生成し、 AppAuthenticator
とし、コントローラーを SecurityController
と命名し、 logout
URLを生成しましょう(yes
)。
このコマンドはセキュリティ設定を更新し生成されるクラスとワイヤリングします:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -16,6 +16,13 @@ security:
security: false
main:
anonymous: lazy
+ guard:
+ authenticators:
+ - App\Security\AppAuthenticator
+ logout:
+ path: app_logout
+ # where to redirect after logout
+ # target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
コマンド出力のヒントにあるように、ログインが成功した際にユーザーをリダイレクトするように onAuthenticationSuccess()
メソッドにあるルートをカスタマイズする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13
--- a/src/Security/AppAuthenticator.php
+++ b/src/Security/AppAuthenticator.php
@@ -49,9 +49,7 @@ class AppAuthenticator extends AbstractLoginFormAuthenticator
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('admin'));
}
protected function getLoginUrl(Request $request): string
Tip
EasyAdminのルートが admin
であることをどうやって覚えていられるでしょうか?( App\Controller\Admin\DashboardController
で設定しました) 覚えていられませんよね。そんなときはコントローラファイルを見ることもできますが、次のコマンドでルート名とパスの関連を表示することもできます:
1
$ symfony console debug:router
認可アクセスコントロールのルールを追加する
セキュリティシステムは2つのパートによって構成されています。 認証 と 認可 です。管理者ユーザーを作成した際に ROLE_ADMIN
ロールを与えています。 access_control
にルールを追加して、 ROLE_ADMIN
ロールを持ったユーザーのみが /admin
セクションにアクセスできるようにしましょう:
1 2 3 4 5 6 7 8 9 10 11
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -35,7 +35,7 @@ security:
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- # - { path: ^/admin, roles: ROLE_ADMIN }
+ - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
access_control
のルールは正規表現でアクセスを制限します。 /admin
から始まる URL にアクセスされると、セキュリティシステムは、ログインしているユーザーが ROLE_ADMIN
ロールがあるかチェックします。
ログインフォームで認証する
これで、管理者のバックエンドへのアクセスを試みると、ログインページにリダイレクトされ、ログインとパスワードの入力を促されるはずです:
admin
と先ほど選んだパスワードを使ってログインしてください。 そのまま SQL をコピーしていたなら、そのパスワードの値は admin
です。
EasyAdmin は自動的に Symfony の認証システムを検知します:
"ログアウト" リンクをクリックしてください。これで、管理者のバックエンドはセキュアな状態になります。
Note
make:registration:form
コマンドを使えば、より高機能な認証システムを作成することができます。
より深く学ぶために
- Symfony セキュリティのドキュメント;
- SymfonyCasts セキュリティチュートリアル;
- Symfony アプリケーションでの ログインフォームの作り方;
- Symfony セキュリティのチートシート.