Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5認証編②】画面デザインやBASIC認証等

A子

えーっと、とりあえず前に作ったやつ(「bbsapp」の各ファイル)を「authapp」プロジェクトにコピーしよう

1.configディレクトリ内の「const.php」をコピーして書き換え
2.configディレクトリ内の「bootstrap.php」の書き換え(「const.php」を読み込ませるように)
3.configディレクトリ内の「routes.php」を書き換え(Topのindexをルートにする)
4.webroot/cssディレクトリ内の「paginate.css」をコピー
5.templates/layoutディレクトリ内の「default.php」をコピーして書き換え(ただし、styleタグについては削除)
6.templates/Postsディレクトリ内の「index.php」をtemplates/Topディレクトリへコピーしてから内容を修正
7.templates/Usersディレクトリの「login.php」「index.php」「view.php」「add.php」「edit.php」の五つをCSSフレームワーク(Bulma)に合わせて修正

…って感じでどうかな?

C菜

良いと思います~

A子

まずは1番ね

1.configディレクトリ内の「const.php」をコピーして書き換え

A子

次は2番

2.configディレクトリ内の「bootstrap.php」の書き換え(「const.php」を読み込ませるように)

A子

んで、3番

3.configディレクトリ内の「routes.php」を書き換え(Topのindexをルートにする)

A子

4番はコピーしただけ

4.webroot/cssディレクトリ内の「paginate.css」をコピー

A子

5番もほとんど変更なし
(CSSフレームワークには「Bulma」を使うよ)

5.templates/layoutディレクトリ内の「default.php」をコピーして書き換え(ただし、styleタグについては削除)



A子

6番はめっちゃシンプル
リンクが二つあるだけ)

6.templates/Postsディレクトリ内の「index.php」をtemplates/Topディレクトリへコピーしてから内容を修正

A子

7番については、五つのビューファイルを順番に示していくわね

7.templates/Usersディレクトリの「login.php」「index.php」「view.php」「add.php」「edit.php」の五つをCSSフレームワーク(Bulma)に合わせて修正






C菜

すごいです~

プログラマにとっての財産は、過去の経験だってことがよくわかりますね~

B美

あと、BASIC認証も組み込むようにね

ユーザ管理機能(index,view,add,edit,deleteの各メソッド)については、管理者だけがアクセスできるように!

A子

とりあえず定数ファイル(const.php)に管理者IDとパスワードを追加しよう

ん?
前回はdeleteメソッドだけだったけど、今回はメソッドが五つもあるね

どうすりゃいいのさ?

B美

スマートなのは、配列に(BASIC認証の)対象メソッドを列挙することかしら

前回(bbsapp)は

if ($action == 'delete') {
    ・・・
}

だったけど、今回(authapp)は

$protectedActions = ['index', 'view', 'add', 'edit', 'delete'];
if (in_array($action, $protectedActions, true)) {
    ・・・
}

…って感じで、「in_array」関数を使うのよ

C菜

五つの条件式($action == '…')をOR(||)で繋げていくよりも美しいです~

A子

なるほどね
それじゃ、bakeコマンドで「HttpBasicAuth」を組み込んだあと、「src/Middleware」の中にある「HttpBasicAuthMiddleware.php」を書き換えるよ

ちなみに、基本は「bbsapp」からのコピペだけど、さっきB美から教わった箇所と認証失敗時にトップページへ戻るときのリンクなんかは適宜変更してるからね


A子

あと、「src/Controller」の中にある「UsersController.php」には「initialize」メソッドを追加したよ

B美

ふむ、さすがに手慣れたものね

それじゃ、ブラウザで確認してみましょう
まずはログイン画面

C菜

ログイン直後はこうなりましたよ~

ここで「ログアウト」をクリックしてみましたけど、きちんと「ログイン」画面に戻ることを確認できました~

A子

んじゃ、右端にある「ユーザ管理」をクリックすると…
うん、BASIC認証のIDとパスワードの入力画面が出たね

ここに正しい管理者IDとパスワードを入れると、この画面(ユーザ管理画面)になったよ

C菜

表示」をクリックしてみます~

A子

一覧に戻ったあと、次は「編集」をクリックしてみたよ

B美

うーん、「ユーザID」については表示するだけにして、変更ができないようにしておくべきだと思うわよ

まぁ、それはともかく…
とりあえずは別のパスワードを入力して「更新」ボタンを押してみましょうか

うん、問題なく更新されたみたいね

C菜

次は「新規ユーザ登録」です~

A子

二人目のユーザを登録してみたんだけど、どうやらうまくいったみたいだね

んで、たった今、登録したやつをすぐに「削除」してみたけど、これも成功したよ

B美

あ、そうだ
現在ログイン中のユーザは削除できないようにしておかないとダメよ
(「削除」リンクを表示しないようにする)

でもまぁ、なかなかのものね
(思ったよりもよくできてるわ)

C菜

それじゃあ、B美部長ご指摘の点を修正していきましょう~

まずは「編集」時、「ユーザID」を編集対象にしない点ですね~

A子

それはすぐにできるよ

「$this->Form->text」の箇所を「h($user->email)」に変えれば良いんだよね?

A子

問題はログイン中であるかどうかをどうやって調べれば良いのか…

C菜

その「ログイン中」って、自分自身だけのことですか~?

それとも他のユーザも含めての話でしょうか~?

A子

あっ!そっか…

うーん、自分以外のユーザのログイン状況って、調べるのは難しいかな?

B美

もしも「自分自身だけ」で良いのなら簡単よ

$this->Authentication->getIdentity()

で、現在ログインしているユーザ情報(自分自身の情報)を得られるし、

$this->Authentication->getResult()

の戻り値を使って「isValid」メソッドを呼び出せば、自分がログイン状態であるかどうかを知ることができるわよ

ほら、「UsersController.php」でも使ってたでしょう?
(下記参照)

A子

あ、わかったよ

ユーザ管理画面でユーザの一覧を表示する際、「getIdentity」で取得したユーザIDと同じユーザだった場合は、「削除」リンクを表示させなければ良いんじゃない?

C菜

ん~?

あっ、たしかにうまくいきそうです~

A子

とにかく、あれこれ悩むよりも手を動かそう

「src/Controller」の中にある「UsersController.php」の「index」メソッドをこう変えてっと…

C菜

それでは「templates/Users」の中にある「index.php」を次のように変えますね~

B美

事前準備として、あらかじめ私たち三人分のユーザを作っているんだけど…

私(bimi@friction-river.jp)がログインして「ユーザ管理画面」を開いた場合、こうなるわね

A子

おぉ、バッチリじゃん

一発で成功って、ちょっとすごくない?

B美

はいはい(苦笑)

まぁ、ユーザ名(ハンドルネーム)を常にページの右上に表示したりする場合は、共通処理として「AppController.php」なんかに記述するほうが良いかもしれないけどね
(てか、それが一般的)

C菜

それはなぜでしょう~?

B美

「AppController」クラスが全てのControllerコントローラースーパークラス(親クラス)だからよ
普通のControllerコントローラーって、「AppController」クラスのサブクラス(子クラス)になるの

そうねぇ
例えば、「TopController.php」を見てみましょうか

class TopController extends AppController

の後半「extends AppController」というのは、「AppController」クラスを「継承」する…って意味なのよ

A子

まーた、わけのわからないことを言い始めたよ、こいつ…

継承」って何なのさ?

C菜

あれ~?
以前その言葉を聞いたような~?

はっ、オブジェクト指向の説明のときです~
(CakePHP5基礎編②を参照)

B美

さすがはC菜ね

そう、あのときって「カプセル化」だけ知っていればOK…って言ったんだけどさ
全てのControllerコントローラーに共通する処理を書きたいんだったら、「継承」の知識が必要になってくるのよ

A子

うへぇー

まーた、難しい話じゃないでしょうね?

B美

いいえ、簡単な話よ

そうねぇ、最低限これだけを知っていれば良いわ
元となるクラスを継承して作った新たなクラスは、元クラスの能力を全て受け継ぐ」と…

C菜

えっと~

「TopController」クラスや「UsersController」クラスは「AppController」クラスを継承しているので~
両クラスとも「AppController」クラスの能力を受け継いでいるってことですか~?

言い換えれば、「AppController」クラスに記述した内容は、全てのControllerコントローラーで共有される?

B美

その通り!
あと、用語としては

・継承元となるクラスを「スーパークラス」または「親クラス
・継承先となるクラスを「サブクラス」または「子クラス

と呼ぶの

そうねぇ、こう覚えておけば良いわ
子は親の能力を全て受け継ぐ」と…

A子

なるほどねぇ

それじゃ、「AppController.php」の中に「initialize」メソッドを作って、その中にさっきの

$identity = $this->Authentication->getIdentity()
$this->set(compact('identity'));

を書けば良いの?

B美

違う違う!

一度しか実行されない「initialize」メソッドではなく、各メソッドを呼び出す際、その前に必ず実行される「beforeFilter」メソッドの中に書くべきね
(「beforeRender」メソッドに書くべきである…って人もネット上にはいるけど…)

A子

うーん、とにかくやってみよう

まずは「src/Controller」の中にある「AppController.php」を開いて「beforeFilter」メソッドを追加するよ
(てか、「UsersController.php」からコピペして書き換えた)

C菜

さきほど書き換えた「UsersController.php」の「index」メソッドは元に戻しておきますね~

B美

本当に共通処理になっているかを検証するために、「templates/layout」の中にある「default.php」を書き換えてみなさい

あ、ただし「$identity」がnullであるかどうかのチェックは入れること!

A子

OK、OK

こんな感じで、ページの右端にユーザIDを表示するようにしてみたよ

C菜

実際にブラウザで表示してみたのがこれです~

ちなみに、右上にあるB美部長のユーザID(メールアドレス)は、ユーザ管理画面に切り替えても表示されますし、(当然ですが)ログインページでは表示されませんよ~

A子

完璧じゃん

あ、でも他のユーザのログイン状況は分からないよね?

B美

それを知るには、データベースの「users」テーブルに新たな項目(例えば「status」)を追加して、ログイン・ログアウトの際にその項目の値を書き換える…って方法しかないかな?

ただ、あまりあてにならないんだけど…(苦笑)

A子

何でよ?

B美

全てのユーザがきちんと「ログアウト処理を行ってくれるか分からない」からよ

例えば、ログイン中にブラウザを閉じちゃったり、スマホなんかだと(ログインしたまま)ブラウザを非表示にしたり…

C菜

あ、しかもログイン処理にはセッションを使っていると思うんですけど~

セッションって時間経過で無効になりませんでしたっけ~?
(いわゆる「セッションタイムアウト」)

B美

なるわよ
(セッションタイムアウトは必ず発生するわ)

その時間って自由に設定できるんだけど、(CakePHP5では)「config」ディレクトリの中にある「app.php」で設定するの

んで、もしも設定されてなければ(というか、デフォルトでは設定されてない)、自動的に「php.ini」の「gc_maxlifetime」が適用されて、持続時間は1440秒(24分)ってことになっているわね
(下記参照)

ちなみに「app.php」内にセッション持続時間を記述する場合、その時間単位は「分」だから気を付けてね
(「秒」のつもりで1440にしちゃうと、24時間って意味になっちゃうから(苦笑))

A子

なるほど

セッションタイムアウトで勝手にログアウト状態になっても、データベース的にはログイン状態ってこともあるのか…
(「logout」メソッドを呼び出していないから)

B美

まぁ、ユーザに「ログアウトする」ことを徹底しておけば、問題は生じないんだけどね

絶対に(ログイン状態で)うっかりブラウザを閉じちゃう人はいるだろうし…(苦笑)

A子

それに関しては、決して否定できない私がいる(笑)