2

私は2つのメインテーブルを持っています:

  1. 本 (id、著者、isbn、...)
  2. ユーザー (ID、ユーザー名、パスワードなど)

User1 がログインして次のことができるアプリケーションの構築を検討しています。

  1. すべての書籍のリストを表示 (例: タイトルのみ)
  2. 彼がアクセスできる特定の書籍のみの詳細 (著者、ISBN など) を表示する

各ユーザーは、特定の書籍セットにアクセスできます。いろいろな役割はいらない。

上記のMVCと関係(habtm)をセットアップしました。私は今、権限の開発を検討しています。CakePHP の ACL はこの問題を解決すると思いますか?それともやり過ぎだと思いますか?

やり過ぎである場合、目的の機能を構築するための別のコンポーネントまたはより簡単な方法はありますか?

4

2 に答える 2

1

はい、ACL はやり過ぎです

ACL は非常に強力で柔軟なシステムですが、無料で提供されるわけではなく、複雑さが伴います。きめ細かいアクセス許可が絶対に必要なユースケースがない限り (説明した 2 つのルールはこれに当てはまりません)、ACL を使用しないでください。

彼が追加したユーザーを書籍に制限する

このルールは簡単に実装できます。たとえば、関連する検索呼び出しに追加します。

$results = $BookModelInstance->find('all', array(
    'conditions' => array(
        'created_by' => AuthComponent::user('id')
    )
));

ユーザーが購入した書籍に限定する

このルールも簡単に実装できますが、少し複雑になります。

$BookModelInstance->bindModel(array(
    'hasOne' => array( // Yes, hasOne not hasMany
        'MyPurchase' => array(
            'className' => 'Purchase',
            'foriegnKey' => 'user_id'
        ) 
    )
));
$results = $BookModelInstance->find('all', array(
    'recursive' => 0, // to join hasOne+belongsTo associations into the query
    'conditions' => array(
        'MyPurchase.user_id' = AuthComponent::user('id'),
    )
));

bindModel 呼び出しは . と同等のものを実現しSELECT .. FROM books LEFT JOIN book_usersます。したがって、find 呼び出しの条件により、ユーザーが本を購入したという記録がある本に結果が制限されます。

両方を一緒に置く

これらの両方のルールを自動的に適用する単純な実装は次のようになります。

model Book extends AppModel {

    public $actsAs = array('Containable');

    public $restrictToUser = true;


    public function beforeSave($options = array()) {
        if (!$this->id) {
           // Store who created this book
           $this->data[$this->alias]['created_by'] = AuthComponent::user('id');
        }
        return true;
    }

    public function beforeFind($queryData) {
        if (!$this->restrictToUser) {
            // we don't want to apply user-level restrictions
            return true;
        }

        $userId = AuthComponent::user('id');
        if (!$userId) {
            // we want to restrict to the current user - there isn't one.
            return false;
        }

        // define the association to the purchase table
        $this->bindModel(array(
            'hasOne' => array(
                'MyPurchase' => array(
                    'className' => 'Purchase',
                    'foriegnKey' => 'user_id'
                ) 
            )
        ));

        //ensure the purchase table is included in the current query
        $queryData['contain']['MyPurchase'] = array();

        // restrict to rows created by the current user, OR purchased by the current user
        $queryData['conditions']['OR'] = array(
            $this->alias '.created_by' => $userId,
            'MyPurchase.user_id' => $userId
        );
        return $queryData;
    }
}

これにはフィールドcreated_by(または同等のもの) が books テーブルにある必要があり、containable を使用してpurchasesテーブル (または同等のもの) が関連するすべてのクエリに含まれるようにします。

于 2013-01-13T13:39:31.147 に答える
0

最も簡単な解決策: コントローラーに条件を追加します。

$this->set('books', $this->Book->find(
    'all',
    array('conditions' => array('Book.user_id' => $user['User']['id']))
);

短所: このチェックは他の場所でも行う必要があるため、ここで重複するコードを作成する可能性があります。また、モデルのテストを開始するときは、書籍を返すことのみをテストできます。getMyBooks($userId) のようなモデル メソッドをテストすることはできません。いいえ、好ましい解決策ではありません。

次の解決策: モデルをチェックインする

たとえば、書籍モデルをチェックインすることで実行できます。返されたレコードが許可されているかどうかを afterfind() メソッドで確認できます。beforefind では、すべてのクエリに条件を追加することもできます。

一般に、モデルは太っていなければならないので、getAllBooks、getBooksOfUser($User)、getLatestBooksOfUser($User) などの明確なメソッドを実装することをお勧めします。

なぜこれが良い実装なのですか? 中央の場所でアクセス レベルを管理できるようになったからです。モデルをテストすると、このユーザーからの書籍のみが返されることを確認できます。

beforeSave などを使用すると、すべての保存試行に介入して、最初に確認できます。ねえ、これを保存したいのですが、これは本当にあなたの本ですか?

ACL ソリューション

しかし、一般的には、何らかの ACL ソリューション (できれば組み込みのソリューション) を実装することが賢明です。これにより、アプリケーションの将来性が大幅に高まるからです。これにより、次のような柔軟性が得られます。

各ユーザーは、特定の書籍セットにアクセスできます。いろいろな役割はいらない。

それは今のところ真実ですが、将来はそれを変えることができます。したがって、迅速な解決策が必要な場合は、レコードをカスタム フィルターするだけです。しかし、将来について考えてみてください。

于 2013-01-13T12:12:26.230 に答える