はじめに
会社に入社して業務のために、php(cakephp)を学ぶ研修で、cakePHPのチュートリアル(主にBlog)をしたときに、つまずいた点を記事として残そうかと思います。
*ブログチュートリアル
https://book.cakephp.org/3/ja/tutorials-and-examples/blog/blog.html
つまずいた所
*admin権限ではないユーザーがログインした場合のアクション権限
=>ユーザーが投稿した記事のみ編集・削除できる機能実装(ほんとに最後...)
認可(誰が何にアクセスするのを許可するか)
ログインしてるのか・してないかでアクセスを分ける
まずユーザーの種類にadmin(管理者)とauther(著者)の2種類あります。
そこの使い分けはまず、全体に認証をかけたいようなときはAppControllerappcontrollerでAuthコンポーネントの設定します。
*ちなみに、コントローラの拡張をコンポーネント!モデルはビヘイバー!Viewはヘルパーというものがあります。
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [ //Authコンポーネントの読み込み
'authorize' => ['Controller'],
'loginRedirect' => [ //ログイン後のリダイレクト先
'controller' => 'Articles',
'action' => 'index'
],
'logoutRedirect' => [ //ログアウト後のリダイレクト先
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
続きにAppContorollerに
//isAuthorizedはAuthコンポーネントで定義されている!
public function isAuthorized($user)
{
// roleというカラムで、adminを定義して管理者はすべての操作に権限を与える
if (isset($user['role']) && $user['role'] ==='admin') {
return true;
}
//その他のロールの場合はデフォルトで拒否とする(許可したい場合は各コントローラで個別に設定)
return false;
}
// 共通メソッド beforeFilterでコントローラーのメソッドよりも先に実行する(ロールバック)
public function beforeFilter(\Cake\Event\Event $event)
{
//beforeFilterでisAuthorizedメソッドよりも先に実行してくれるので
//認証なしでアクセスできるアクションの指定
$this->Auth->allow(['index', 'view', 'display']);
$this->set('auth', $this->Auth->user());
}
ユーザーの権限
AppConroller 内でやるかわりに、 各個別のコントローラーにさらなるルールを追加します。
追加しようとしているルールというのは、 ArticlesController によって、著者は記事を作成できるが、 自分のものではない記事を編集・削除できないようにする、というもの(本題)。
まずはArticlesControllerの編集
//Authコンポーネントで定義されているメソッド(認証済みであるという意味)
public function isAuthorized($user)
{
//addアクションのリクエストであればtrueを返す = つまり登録ユーザー全員が記事を追加できます
if ($this->request->getParam('action') === 'add') {
// LoginUserであれば実行可能なので、trueを返す
return true;
}
//(in_array — 配列に値があるかチェックする) 編集や削除のリクエストである場合
if (in_array($this->request->getParam('action'), ['edit', 'delete'])) {
//pass.0はURL内で渡されたパラメータを表します、つまりURLのアクションの下のパスセグメント( / で区切ったキーワード)を数字をインデックスとする配列で呼べるようにする。
//'pass.0' とインデックスを指定すると配列の先頭要素、つまりパスセグメントの先頭要素を取り出せる。
$articleId = (int)$this->request->getParam('pass.0');
// actionがedit,deleteの場合、request($articleId)の値とuserテーブルのuser_idの比較を行う。
if ($this->Articles->isOwnedBy($articleId, $user['id'])) {
//一致すればtrueを返して、編集削除を許可する
return true;
}
}
// 比較がfalseの場合、AppControllerのisAuthorizedへ、
// 権限が'admin'の場合はtrue、それ以外はfalse。
return parent::isAuthorized($user);
}
}
ちなみにisOwnedByはarticleテーブルで定義する!
public function isOwnedBy($articleId, $userId)
{
return $this->exists(['id' => $articleId, 'user_id' => $userId]);
}
モデルのアソシエーション
関係するモデルはArticlesテーブルとUsersテーブルが関係あります。
ここが大事!
つまり、投稿した記事のidとログインしたuser_idとが紐付かなければなりません!
アソシエーションを組みます!
ArticlesTable
public function initialize(array $config)
{
parent::initialize($config);
$this->table('articles');
$this->displayField('title');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
// アソシエーション
//*foreignKeyはリレーションする「先」のテーブルの、紐づけるカラム(外部キー)
$this->belongsTo('Users', ['foreignKey' => 'user_id']);
$this->belongsTo('Categories', ['foreignKey' => 'category_id']);
}
*ここで迷ったのは、Userstable.phpもアソシエーション 定義しないでいいの???
今回は投稿した記事(=ArticlesControllerのaddアクションのみ)なのでいりません!!
これで、ArticlesControllerでusersテーブルでのデータを持ってくることができます!
最後にコントローラーのメソッド!!
投稿した記事(addアクション)にuser_idを紐付ける
// 記事追加機能
public function add()
{
//newEntityとは 新規追加、保存処理をするときに使用新しく保存されるときにデータの検証が行われる
$article = $this->Articles->newEntity();
//コントローラの処理でHTTPリクエストメソッドが「Post」でない場合はエラーに飛ばす、
if ($this->request->is('post')) {
//ここでuserテーブルのuser_idと紐付けてくれる(ここ大事です!!)
$article->user_id = $this->Auth->user('id');
// patchEntity メソッドは、データがエンティティーにコピーされる前に 検証を行います
$article = $this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $article);
$categories = $this->Articles->Categories->find('treeList');
$this->set(compact('categories'));
}
これで無事に投稿した記事とuser_idが紐付きました!
先ほどArticlesControllerで定義したisAuthorizedメソッドが効いてアクセス制限を分けることができました!!
最後に
デバックしたりすることで、今回のエラーをがアソシエーション されてない事に気付き対処することができました!
参考
https://sites.google.com/site/kobashijiangyiyong/detabesu/e-detabesu-she-ji-yan-xi-3-4