この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
前回に引き続き、部署別のアクセス制限を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のシンプルな構造のメリットと言えるかと思います。