eccube4系の管理画面やマイページのログイン機能は、SymfonyのSecurityをもとに構築されています。
このSecurityのシステムが強力で、security.yamlに設定を書いておけば、特定の特定のURLには、ログインが必要といった実装がかなり楽に実装できます。
今回はeccube4系の実装をみて理解していきます。
eccube4の場合security.yamlのパスは、app/config/eccube/packages/security.yamlにあります。
またアクセスコントロールの設定は別ファイルsrc/Eccube/DependencyInjection/EccubeExtension.phpに書かれています。
security:
encoders:
Eccube\Entity\Member:
id: Eccube\Security\Core\Encoder\PasswordEncoder
Eccube\Entity\Customer:
id: Eccube\Security\Core\Encoder\PasswordEncoder
providers:
member_provider:
id: Eccube\Security\Core\User\MemberProvider
customer_provider:
id: Eccube\Security\Core\User\CustomerProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: '^/%eccube_admin_route%/'
anonymous: true
provider: member_provider
form_login:
check_path: admin_login
login_path: admin_login
csrf_token_generator: security.csrf.token_manager
default_target_path: admin_homepage
username_parameter: 'login_id'
password_parameter: 'password'
use_forward: false
success_handler: eccube.security.success_handler
failure_handler: eccube.security.failure_handler
logout:
path: admin_logout
target: admin_login
customer:
pattern: ^/
anonymous: true
provider: customer_provider
remember_me:
secret: '%kernel.secret%'
lifetime: 3600
name: eccube_remember_me
remember_me_parameter: 'login_memory'
form_login:
check_path: mypage_login
login_path: mypage_login
csrf_token_generator: security.csrf.token_manager
default_target_path: homepage
username_parameter: 'login_email'
password_parameter: 'login_pass'
use_forward: false
success_handler: eccube.security.success_handler
failure_handler: eccube.security.failure_handler
logout:
path: logout
target: homepage
access_decision_manager:
strategy: unanimous
allow_if_all_abstain: falseあと、eccube4の特徴としてアクセスコントロールの設定が、src/Eccube/DependencyInjection/EccubeExtension.phpに書かれています。
security.yamlに書けば、設定をsecurity.yamlのみに集約できるため読みやすいですが、
あえてこちらに書かれているのは、動的に設定値を設定したい機能があるためと思われます。
↓src/Eccube/DependencyInjection/EccubeExtension.php
$accessControl = [
['path' => '^/%eccube_admin_route%/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/%eccube_admin_route%/', 'roles' => 'ROLE_ADMIN'],
['path' => '^/mypage/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/mypage/withdraw_complete', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/mypage/change', 'roles' => 'IS_AUTHENTICATED_FULLY'],
['path' => '^/mypage/', 'roles' => 'ROLE_USER'],
];eccube4ではfirewallsという階層の下に、adminとcustomerが設定されています。
eccube4ではサイト運営者用の管理画面、と会員マイページの画面の2つのログイン制御を行う必要があります。
複数のログインを制御するためにadmin、customerの下にproviderというキーがあり、
そこで、member_providerと、customer_providerが指定されています。
また、その実装クラスは、第2階層のprovidersに指定されています。
管理画面のMemberProviderと会員マイページのCustomerProviderのクラスには、
Core/User/UserProviderInterface.phpのインターフェースが定義されています。
例えばですが、Providersとfirewalls下の値を増やせば、管理画面・マイページ以外の認証機能も追加していくことが可能です。
ログインフォームのパスを指定している部分がform_login下のlogin_pathとcheck_pathです。
/login等のURLまたは、ルート名(eccubeの場合admin_login)を指定することで、
ログイン時のフォームのリダイレクト設定をいい感じにしてくれます。
firewallsを設定しても、これだけでは、ログイン後の画面はセキュアではありません。
後ほど解説するアクセスコントロールの設定と合わせることで認証の制御が可能となります。
参考: https://symfony.com/doc/3.4/security/form_login_setup.html#create-the-correct-routes
アクセスコントロールの解説の前に、anonymous(匿名)について軽く説明します。
管理画面、マイページともにfirewallsの中で、anonymous: trueと設定されています。
anonymous: trueとすることで、匿名のユーザーを作り出します。
また、この匿名ユーザーはログイン前のロールとして使用されます。
(Symfonyのプロファイラーでもanonymousは確認できます。
認証されたユーザーのみ閲覧できるようにする場合は、URLのパターンとロール(Role)で制御します。
eccube4の場合、src/Eccube/DependencyInjection/EccubeExtension.phpの実装がそれに当たります。
(もちろんSecurity.yamlに記載することもできます。)
ログインしていない状態の場合、IS_AUTHENTICATED_ANONYMOUSLYが設定されています。
たとえば/adminのpathとROLE_ADMINのRoleが設定されている場合、
匿名ユーザーの場合、アクセスコントロールで設定されたURLはロール閲覧できません。
管理画面のURLには、ROLE_ADMINつまり管理者としてログインしていないと閲覧できないといった設定をしています。
マイページの場合も同様です。
参考: https://symfony.com/doc/3.4/security.html#add-code-to-deny-access
アクセスコントロールの実装をよくみると、
$accessControl = [
['path' => '^/%eccube_admin_route%/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/%eccube_admin_route%/', 'roles' => 'ROLE_ADMIN'],
['path' => '^/mypage/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/mypage/withdraw_complete', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
['path' => '^/mypage/change', 'roles' => 'IS_AUTHENTICATED_FULLY'],
['path' => '^/mypage/', 'roles' => 'ROLE_USER'],
];マイページの会員情報の編集(/mypage/change)のロールにIS_AUTHENTICATED_FULLYの指定があります。
Securityの機能で以下の特別な属性(ロールに近いもの)があるようです。
IS_AUTHENTICATED_REMEMBEREDIS_AUTHENTICATED_FULLYIS_AUTHENTICATED_ANONYMOUSLYIS_AUTHENTICATED_ANONYMOUSLYはログイン前の状態です。
セッションが続く時間よりも長くログインしたままにすることをユーザーに選択させることができるremember_meの状態によって、
IS_AUTHENTICATED_REMEMBEREDとIS_AUTHENTICATED_FULLYでの認証の結果は変わります。
remember_meのクッキーがブラウザに残っており、セッションが切れている場合に、
IS_AUTHENTICATED_FULLYでは認証に失敗しますが、
IS_AUTHENTICATED_REMEMBEREDは認証に成功します。
マイページの会員登録画面は不正にログインされると問題があるため、
他の画面と異なり、remember meではなく、セッションが保持されているときのみアクセス可能とすることで、セキュリティの強度を上げていると考えられます。
すべての設定値を解説できていないので、eccube4のSecurity.yamlを完全に理解したとまでは言えないですが、
Securityの主要な部分について解説できたかなと思います。
eccube4はSymfonyに則って実装されているので、ドキュメントが豊富です。
本記事はこれで終了ですが、詳しく知りたい方はぜひドキュメントを確認してみてください。(Google翻訳さえあればなんとかなります。)
eccube4の開発は、実装でも迷ったら最悪ドキュメント当たりつつ本体のソースコードを読めばだいたい解決するので、安心感がありますねー。