[Ruby on Rails]sorceryによる認証 – (6)部署別のアクセス制限 #3 コントローラ
はじめに
前回に引き続き、部署別のアクセス制限をsorceryで行うサンプルについてです。今回はコントローラのソースコードを取り上げます。尚、作成したサンプルは以下のGithubに置いてあります。全ソースを見たい方は参考にしてください。
sorcery_api_sample
ソースコード
では、ソースコードです。今回変更した部分のみを載せておきます。
UsersController
module Api module V1 class UsersController (中略) def create respond_to do |format| @user = User.new(user_params) if @user.save_relation(department_params) format.json { render nothing: true, status: :created } else format.json { render nothing: true, status: :bad_request } end end end def update respond_to do |format| if @user.update_relation(user_params, department_params) format.json { render :show } else format.json { render json: @user.errors, status: :unprocessable_entity } end end end (中略) private def department_params params.require(:department).permit(:department_id) end
ユーザ情報を登録するcreateアクションではUserモデルのsave_relation()メソッドを、updateアクションではupdate_relation()メソッドを呼び出しています。メソッドについては前回を参照してください。また部署のIDをパラメータとして取得するためdepartment_params()を追加しています。
ApplicationBaseController
全てのコントローラ(今回はAPIのバージョンV1の場合)の親クラスとなるApplicationBaseControllerには、管理部のユーザのみ参照を許可するfilterを追加しました。
module Api module V1 class ApplicationBaseController < ApplicationController before_action :require_valid_token (中略) def administrator_only access_token = request.headers[:HTTP_ACCESS_TOKEN] api_key = ApiKey.find_by_access_token(access_token) user = User.find(api_key.user_id) if user.user_department.department_id != Department::ADMINISTRATOR respond_to do |format| format.json { render nothing: true, status: :unauthorized } end end end
リクエスト時に送られてくるAccessTokenよりユーザ情報を取得し、その所属部署のIDが管理部かどうかを判定しています。「user.user_department.department_id」というようにUserモデルから関連するUserDepartmentモデルを参照できるのは、前回モデルにhas_oneなどの関連の定義をしたためです。
SampleController
最後にユーザの所属部署ごとにアクセス制限を行うSampleControllerについてです。こちらは前回記述した分も含め、全てのソースコードを載せておきます。
module Api module V1 class SampleController < Api::V1::ApplicationBaseController skip_before_filter :require_valid_token, only: :public before_filter :administrator_only, only: :admin def public @message = 'public' end def restrict @message = 'authorized' end def admin @message = 'admin' end end end end
ログインしていないユーザを含め全ユーザに公開するpublicアクションは「skip_before_filter」でログインのチェックを行わないようにしています。
管理部のユーザのみ参照させるadminアクションは「before_filter」でadministrator_only()を呼び出すことにより、これを実現しています。
ログインしているユーザは部署を問わず参照させるrestrictアクションについては以前から変更無く、ApplicationBaseControllerの「before_action」でログイン済みユーザかをチェックしています。
まとめ
以上で部署別のアクセス制限を行う実装については以上になります。ユーザの所属部署をUserテーブルとは別テーブルに保持したことにより、sorceryのソースには一切触れない形での実装となりました。このような作り込みが必要にはなりますが、一方既存のデータ構造を変更すること無しに実現できることは、sorceryのシンプルな構造のメリットと言えるかと思います。