Top > 開発ガイド > コンポーネント開発Tips集 > モデルベース承認
モデルベース承認
対象バージョン
当ドキュメントはRubricks-0.6.x向けです。
概要
Rubricksはグループベースのアクセス制御の仕組みを持っています。 それに加えて、モデルベース承認を宣言的に制御できるライブラリを準備しています。
モデルベース承認とは、アクセスしてきたユーザが、そのアクセスで取り扱うモデルを触る権限があるかどうかで制御を行うものです。 Railsであれば
http://xxxx.com/component/controller/show/1
と言った形でモデルのIDを指定して情報参照することが一般的です。
その場合、本来見ることができないモデルのIDを直接URL欄などから入力された場合に情報を表示できなくする必要があります。 本ライブラリはその処理を宣言的に実現する機構を提供します。
例えば、下記のようなアプリケーションを作成したい場合に利用できます。
- 自分のTodoは他のユーザには見られてはならない
- 部下の報告書は上司及び同僚のみが閲覧できる
- 勤務報告書は上司または勤務報告コンポーネント管理者のみが閲覧できる
注意 本ライブラリは、直接アクセスによる不正なアクセスに対応するためのものであることに注意して下さい。 正常なユーザが正常にアクセスしてきた場合の挙動は従来どおり実装する必要があります。
サンプル
- モデルは下記のような構成とします。
- created_byはREPORTSを作成したユーザのID
REPORTSテーブル
| id | title | contents | created_by |
| 1 | 報告書1 | 報告します・・・ | 3 |
| 2 | 報告書2 | 報告ですが・・・ | 4 |
- コントローラにauthorize_by_modelメソッドを宣言的に記述します
- ビューでリクエストパラメータで「キー名:id、値:モデルのID」を指定します
controller
class XxxController < ApplicationController
authorize_by_model Report, :auth_action => {:only => :show}, :auth_type => :owner
def main
#...
end
def update
#...
end
def show
#...
end
end
view
<%= link_to 'click', :controller => 'xxx', :action => 'show', :id => 1 %>
結果
ユーザIDが3のユーザ(ID=1のREPORTSのowner)でログインしていれば、showアクションを実行することができる。 そうでなければ、不正アクセスとしてはじかれる。
処理の流れ
- IDが3のユーザでログインしてビューのclickリンクを押すと、
- XxxController?のshowメソッド宛てにパラメータ「id : 1」でリクエストが飛ぶ
- showアクションが実行される前にフィルタでチェックが走る
- Report.find(@params[:id])を実行し、REPORTSテーブルからモデルを取得する
- 取得したモデルのcreated_byで紐づくユーザを取得する
- シンボル:ownerからOwnerAuth?クラスが認識される。
- OwnerAuth?クラスで取得したユーザとログインユーザが等しいか判断
- 等しければshowアクションを実施する
- show以外のアクションにはフィルタが張られていないので通常通りのアクセスとなる
規約(Convention over Configuration)
本ライブラリは下記の規約に則ることで記述量を削減できます。 これらの規約に則らない場合は、オプションで明示的な指定が必要になります。
- モデルのownerを示す外部キーカラム名を「created_by」にする
- 指定モデルIDのリクエストパラメータ名を「id」にする
API
authorize_by_model モデル名, オプション
引数の説明
| 引数 | 初期値 | 説明 |
| モデル名 | 必須 | 承認の条件となるモデル。!ActiveRecord::Baseを継承している前提。 |
| オプション | 下記参照 | ハッシュとして入力する。詳細は下記参照。 |
オプション
| キー名 | 初期値 | 記述可能な型 | 説明 |
| :model_id_in_param | :id | Symbol/String | モデルのIDが格納されているとみなされる@paramsのキー値を指定する。 |
| :owner | :created_by | Symbol/String | モデルownerを示す、モデルテーブルの外部キー名を指定する。 |
| Proc | モデルownerのインスタンスを返却させるようにする。 | ||
| :auth_type | :owner | Symbol/String | 承認方法を示すシンボル名。デフォルトでは:any(誰でもOK), :nobody(誰でもNG), :owner(自分自身だけがアクセス可)が指定できる。 |
| Hash | :component, :functionを渡した場合、該当コンポーネントのfunctionの権限を持っていればアクセスできる。 | ||
| Proc | true/falseを返却することで承認するかを決められる。シンボルを返却すると、上記シンボルを指定した場合と同様の承認がなされる。 | ||
| Array | 上記Symbol,Hash,Procを入れ込むことができ、or条件で判定する。 | ||
| :auth_action | {} | Hash | アクセス制御対象のアクションを指定する。フォーマットはfilterのオプションに順ずる(:only,:exceptなど) |
| :category | nil | Symbol/String | モデルクラスのカテゴリをしめすカラム名を指定する。カテゴリが異なるモデルを取り扱おうとすると不正アクセスとしてはじかれる。指定しなければ無視される。 |
| :params | {} | Hash | 各Procにパラメータとして引き渡される値。@paramsの値とマージされる。 |
使用例集
アクセス制御するアクションを指定する
authorize_by_model Report, :auth_action => {:only => :show}
authorize_by_model Report, :auth_action => {:except => :show}
自分のモデルは自分しかアクセスできないようにする
authorize_by_model Report, :auth_type => :owner
状況によってauth_typeを切り替える
authorize_by_model Report, {
:auth_type => lambda{|owner_user, current_user, model, param|
Date.today.year < 2006 ? :owner, :any
}
}
自分自身かsystemコンポーネントのaccess権限があればアクセスできるようにする
authorize_by_model Report,{
:auth_type => [:owner, {:component => :system, :function => :access}]
}
自分自身で、かつsystemコンポーネントのaccess権限があればアクセスできるようにする
authorize_by_model Report, :auth_type => :owner
authorize_by_model Report, :auth_type => {:component => :system, :function => :access}
「created_by」以外の外部キー名でownerを参照する
authorize_by_model Report, :owner => :owner_id
交差テーブルで紐づくownerを参照する
authorize_by_model Report, {
:owner => lambda{|model, current_user, params|
model.xxx.rubricks_user
}
}
独自の判定基準でアクセス制御をする
- 独自のauth_typeを追加できる
- :auth_typeにシンボルを指定すると、「シンボル+'Auth'のキャメルケース」クラスのauthorizeメソッドを呼ぶ
class OriginalAuth def self.authorize(owner_user, current_user, model, params) Date.today.year < 2006 end end
authorize_by_model Report, :auth_type => :original
- クラス名にモジュール名がついている場合、シンボルでは「::」の代わりに「/」で記述する
class Sample::GoodAuth def self.authorize(owner_user, current_user, model, params) true end end
authorize_by_model Report, :auth_type => :'sample/good'
@params[:id]以外のパラメータでモデルのIDを扱う
authorize_by_model Report, :model_id_in_param => :model_id
params[:id]にユーザID自体が渡ってくる場合を扱う
authorize_by_model RubricksUser, {
:owner => :id,
:auth_type => [:owner, {:component => :abc, :function => :admin}],
:auth_action => {:only => [:show_user, :update]}
}
