Ruby
Rails
rack
権限

BtoBアプリケーションの権限設定

More than 1 year has passed since last update.

目的は権限設定なのですが、内容はcurrent_userをmodelで使う方法になっております。。


背景

Rails+deviseで稼働中のAPIで、ユーザー毎の権限設定を追加したい。

いわゆるSaasで業務システムを開発しています。権限設定もいろいろなパターンがあると思うんですが、今回はデータに触れることが出来るかどうかを制御するパターンです(参照・更新できるかどうかではない)


実装検討

権限設定には大きく分けて2種類ある。。と思う。

1. 機能を制御(主にcontrollerで制御する。参照・更新・削除できるかどうか。)

2. データを制御(modelで制御? あるデータを扱えるかどうか。)

1はイメージしやすい。各APIを使う権限であり、controllerのメソッドを制御できれば良く、cancancan、pundit等のgemがある。

2は主に対象データのあるレコードが参照可能か、更新可能かを制御する。

例えば、ユーザーAは、itemモデルのid:1のデータを更新可で、id:2のデータは参照不可。ユーザーBはid:2だけ更新可のような。

2のようなデータ制御ができるgemを自分は知らない。そこで、current_userをmodelのdefault_scopeで使ってしまうことにした。

本当はcontrollerでできると思うが、controller数もかなり多いので。。


Thread.currentを使う

以下の様に書くと、modelでUser.current_idが使えるようになる。

User.current_id = nil で処理後にクリアしているので、これでも上手く動いていた。

def current_id=(id)

Thread.current[:user_id] = id
end

def current_id
Thread.current[:user_id]
end

around_action :scope_current_user

private

def scope_current_user
User.current_id = current_user.id
yield
ensure
User.current_id = nil
end


request_storeを使う

上記のThread.currentでもできるが、request_storeというgemを使うと、rack層でクリアしてくれる。

authenticated_controller.rbを以下のように変更する。

すると、RequestStore.store[:current_user_id] がmodelで使えるようになる。

  around_action :scope_current_user

private

def scope_current_user
RequestStore.store[:current_user_id] = current_user.id
yield
end

以上で、modelでcurrent_user.idが使えるようになった。 current_user.idでユーザー毎に設定された権限を取得し、default_scopeに条件を追加する。これで、データを制御する権限設定が比較的かんたんに実現できる。

※ default_scopeは本来は使いたくないですね。

他に良い方法があればコメント下さい!!