PHP
Symfony
doctrine
FOSUserBundle

FOSUserBundle: Symfonyでユーザ管理

More than 1 year has passed since last update.


はじめに


The FOSUserBundle, developed by the Symfony community, adds support for a database-backed user system in Symfony. It also handles common tasks like user registration and forgotten password functionality.


FOSUserBundleはSymfonyコミュニティにより開発されており

データベースを使用したユーザ管理システムを提供します。

ユーザ登録やパスワードのリセットなどのよくある機能が実装されています。

Symfonyのインストール時にデフォルトでは入りませんが

ドキュメントがSymfony.com以下にあったり

上記のような記載がベストプラクティスに載っていたりと、信頼できそうです。

基本的な機能や気になったところをまとめます。

:warning: セキュリティに関わることなので、内容を鵜呑みにはしないでください。


環境

Symfonyが動作し、Doctrine経由でMySQLにアクセスできることが前提です。

ソフト
バージョン

PHP
7系

Symfony
3系

MySQL
5.6.x

Doctrine
2.5.3

(バージョン情報の記憶が曖昧なため、後日追記)


導入


インストール

ドキュメントのInstallationに従います。


作成されるページ


ルーティング

自動で多くのページが生成されます。

機能的にはURLパス見たまんまなので詳細は割愛します。

$ bin/console debug:router | grep fos                               

fos_user_security_login GET|POST ANY ANY /login
fos_user_security_check POST ANY ANY /login_check
fos_user_security_logout GET|POST ANY ANY /logout
fos_user_profile_show GET ANY ANY /profile/
fos_user_profile_edit GET|POST ANY ANY /profile/edit
fos_user_registration_register GET|POST ANY ANY /register/
fos_user_registration_check_email GET ANY ANY /register/check-email
fos_user_registration_confirm GET ANY ANY /register/confirm/{token}
fos_user_registration_confirmed GET ANY ANY /register/confirmed
fos_user_resetting_request GET ANY ANY /resetting/request
fos_user_resetting_send_email POST ANY ANY /resetting/send-email
fos_user_resetting_check_email GET ANY ANY /resetting/check-email
fos_user_resetting_reset GET|POST ANY ANY /resetting/reset/{token}
fos_user_change_password GET|POST ANY ANY /profile/change-password


ログイン

1.png


登録

2.png


パスワードリセット

3.png

見た目が簡素ですが、もちろんテンプレートの書き換えはできます。

Overriding Default FOSUserBundle Templates


作成されるテーブル

DBには以下のテーブルが生成されます。

mysql> DESC user;

+-----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(180) | NO | | NULL | |
| username_canonical | varchar(180) | NO | UNI | NULL | |
| email | varchar(180) | NO | | NULL | |
| email_canonical | varchar(180) | NO | UNI | NULL | |
| enabled | tinyint(1) | NO | | NULL | |
| salt | varchar(255) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| last_login | datetime | YES | | NULL | |
| locked | tinyint(1) | NO | | NULL | |
| expired | tinyint(1) | NO | | NULL | |
| expires_at | datetime | YES | | NULL | |
| confirmation_token | varchar(255) | YES | UNI | NULL | |
| password_requested_at | datetime | YES | | NULL | |
| roles | longtext | NO | | NULL | |
| credentials_expired | tinyint(1) | NO | | NULL | |
| credentials_expire_at | datetime | YES | | NULL | |
+-----------------------+--------------+------+-----+---------+----------------+
18 rows in set (0.00 sec)

フィールドごとの役割は以下のとおりです。

ドキュメントに記載が見当たらないので、ソースコードからザッと読んだ内容です。

フィールド
役割

id
ユニークID

username
ユーザ名

username_canonical

usernameをすべて小文字に変換したもの。ユーザ名の重複防止に使用

email
メールアドレス

email_canonical

emailをすべて小文字に変換したもの。メールアドレスの重複防止に使用

enabled
ログイン可能かを示す。未アクティベートユーザのログイン禁止などに使用

salt
パスワードのハッシュ化に使用されるソルト文字列

password
暗号化されたパスワード

last_login
最終ログインの日時

locked
ログイン可能かを示すフラグ。強制的なログイン禁止などに使用

expired
アカウントの有効期限切れを示す。期限が切れているとログイン不可

expires_at
アカウントの有効期限

confirmation_token
パスワードリセットにおける本人確認などに使用されるトークン

password_requested_at
ユーザがパスワードリセットをリクエストした日時

roles
アクセスコントロールに使用されるロール

credentials_expired
認証情報の有効期限切れを示す。定期的なパスワード変更を促すのに使用

credentials_expire_at
認証情報の有効期限


気になったこと


userテーブルに他のフィールドを追加できないのか

必要最低限のフィールドは自動的に作成されましたが

アプリケーションの要件によっては他のフィールドが必要です。

この場合にはエンティティに追加フィールド情報をマッピングできるようです。

例えばアイコン表示用に画像パスを格納したい場合は以下のように記載します。


User.php

/**

* @var string
*
* @ORM\Column(name="image_path", type="string", length=255)
*/

protected $image_path;

その後にスキーマを再更新します。


スキーマの更新

$ bin/console doctrine:schema:update --force


新しくフィールドが追加されているのがわかります。

mysql> DESC user;

+-----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(180) | NO | | NULL | |
| username_canonical | varchar(180) | NO | UNI | NULL | |
| email | varchar(180) | NO | | NULL | |
| email_canonical | varchar(180) | NO | UNI | NULL | |
| enabled | tinyint(1) | NO | | NULL | |
| salt | varchar(255) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| last_login | datetime | YES | | NULL | |
| locked | tinyint(1) | NO | | NULL | |
| expired | tinyint(1) | NO | | NULL | |
| expires_at | datetime | YES | | NULL | |
| confirmation_token | varchar(255) | YES | UNI | NULL | |
| password_requested_at | datetime | YES | | NULL | |
| roles | longtext | NO | | NULL | |
| credentials_expired | tinyint(1) | NO | | NULL | |
| credentials_expire_at | datetime | YES | | NULL | |
| image_path | varchar(255) | NO | | NULL | |
+-----------------------+--------------+------+-----+---------+----------------+
18 rows in set (0.00 sec)

Userエンティティの基本的な作りは他と変わらないので

リレーションを定義することも同様に可能です。


パスワードのポリシー(長さや使用文字制限)は設定できないのか

内部では、Entity、Form、FormTypeなどが使われているので

それぞれにバリデーションを加えることで実現できそうです。

Overriding Default FOSUserBundle Forms

デフォルトの設定はResources/config/validation.xmlにあるから

使うなら使えばいいし、だめならオーバーライドというスタンスなんでしょうか。

Overriding Default FOSUserBundle Validation


ユーザ名を使わないとログインできないのか

installationでの手順ではユーザ名しか使用できませんでしたが

メールアドレスでのログインも許可できるようです。

security.ymlidの部分を変更します。


security.yml

providers:                                       

fos_userbundle:
id: fos_user.user_provider.username_email

これで、ユーザ名とメールアドレスのどちらかでのログインが可能です。

メールアドレスのみを許すことはできませんが、拡張についてPRがありました。

Added email only authentication


まとめ

デフォルトではセキュリティが割と緩めなので

詳細な設定についてはドキュメントをご一読ください。

全体的に「気になるところはオーバーライドして」というスタンスな気がします。

Webのセキュリティ知識や内部実装への理解は必要ですが

上記のような簡単な手順だけで多くの機能を得られるのはお得ですね。