Railsアプリでユーザー権限を管理するための完全ガイド
Webアプリケーションの一般的な要件は、特定の役割と権限を割り当てる機能です。
多くの種類のWebアプリケーションは、制限付きアクセスを提供する際に管理者と通常のユーザーを区別します。これは多くの場合、ユーザーが管理者であるかどうかを判断する単純なブール値を使用して実行されます。ただし、役割と権限ははるかに複雑になる可能性があります。
アプリケーションの価値は、特定のデータとアクションへのアクセスを制限することにあります。それは間違いなくあなたが台無しにしたくないものです。この投稿では、基本的なRubyonRailsアプリケーションにロールと権限を実装する方法について説明します。
権限を管理するためにgemが必要ですか?
いいえ、特にアプリケーションが小さく、コードベースへの依存関係の追加を避けたい場合は、gemは必要ありません。ただし、代替手段を探している場合は、役割と権限を処理する最も人気のあるgemを次に示します。 :
-
DeviseDeviseは、認証と役割管理のための宝石であり、非常に複雑で堅牢なソリューションです。GitHubに21.7kの星があり、この投稿で最も人気のあるリポジトリですが、役割管理以上のことを行います。これは認証ソリューションとして知られているため、非常に堅牢なライブラリが必要な場合にのみコードベースに適用してください。
-
Pundit:Punditは単純なRubyオブジェクトを使用するgemであり、おそらくこれから取り上げる最も単純なポリシーgemです。使い方は簡単で、認証は最小限で、純粋なRubyを使用するのと似ています。 GitHubに7.3kの星があり、現在最も人気のあるポリシーの宝石です。
-
CanCan:CanCanは、特定のユーザーがアクセスできるリソースを制限する認証ライブラリです。ただし、CanCanは何年もの間放棄されており、Rails3以前のリリースでのみ機能します。
-
CanCanCan:CanCanCanは、RubyおよびRubyonRails用のもう1つの認証ライブラリです。これはCanCanの代替であり、現在保守されています。 GitHubに4.9kの星があり、人気は最も低いですが、かなりうまく機能し、よく維持されています。
これらの宝石はすべて素晴らしいですが、プレーンなRubyで自分でパーミッションを構築するのはそれほど難しくありません。ポリシーオブジェクトパターンと呼ばれる戦略を使用して、gemなしで権限を管理する方法を紹介します。
ポリシーオブジェクトは、権限とロールを処理するために使用されるデザインパターンです。何かまたは誰かがアクションを実行することを許可されているかどうかを確認する必要があるたびに、これを使用できます。複雑なビジネスルールをカプセル化し、異なるルールを持つ他のポリシーオブジェクトに簡単に置き換えることができます。すべての外部依存関係がポリシーオブジェクトに注入され、アクセス許可チェックロジックがカプセル化されます。これにより、コントローラーとモデルがクリーンになります。 Pundit、Cancan、Cancancanなどの宝石はこのパターンを実装しています。
- リターンはブール値である必要があります
- ロジックはシンプルである必要があります
- メソッド内では、渡されたオブジェクトのメソッドのみを呼び出す必要があります
命名規則から始めましょう。ファイル名には_policy
があります 接尾辞が適用され、最後にクラスとポリシーがあります。このメソッドでは、名前は常に?
で終わります。 文字(例:UsersPolicy#allowed?
。
次にいくつかのサンプルコードを示します:
class UsersPolicy
def initialize(user)
@user = user
end
def allowed?
admin? || editor?
end
def editor?
@user.where(editor: true)
end
def admin?
@user.where(admin: true)
end
end
どのシナリオでそれらを使用する必要がありますか?
アプリに複数の種類の制限付きアクセスと制限付きアクションがある場合。たとえば、投稿は次のように作成できます。
- 少なくとも1つのタグ
- 管理者と編集者のみが作成できる制限、および
- 編集者を確認する必要があるという要件。
ポリシーオブジェクトのないコントローラーの例を次に示します。
class PostsController < ApplicationController
def create
if @post.tag_ids.size > 0
&& (current_user.role == ‘admin’
|| (current_user.role == ‘editor’ && current_user.verified_email))
# create
end
end
end
上記の条件チェックは長く、醜く、判読できないため、ポリシーオブジェクトパターンを適用する必要があります。
PostsCreationPolicy
を作成することから始めましょう 。
class PostsCreationPolicy
attr_reader :user, :post
def initialize(user, post)
@user = user
@post = post
end
def self.create?(user, post)
new(user, post).create?
end
def create?
with_tags? && author_is_allowed?
end
private
def with_tags?
post.tag_ids.size > 0
end
def author_is_allowed?
is_admin? || editor_is_verified?
end
def is_admin?
user.role == ‘admin’
end
def editor_is_verified?
user.role == ‘editor` && user.verified_email
end
end
ポリシーオブジェクトを持つコントローラーは次のようになります:
class PostsController < ApplicationController
def create
if PostsCreationPolicy.create?(current_user, @post)
# create
end
end
end
Railsでポリシーオブジェクトを使用する方法
アプリ/policies
内にポリシーディレクトリを作成します すべてのポリシークラスをそこに配置します。コントローラを呼び出す必要がある場合は、アクションで直接呼び出すか、before_action
を使用できます。 :
class PostsController < ApplicationController
before_action :authorized?, only: [:edit, :create, :update, :destroy]
def authorized?
unless ::PostsCreationPolicy.create?(current_user, @post)
render :file => "public/404.html", :status => :unauthorized
end
end
end
コントローラで動作をテストするのは簡単です:
require 'rails_helper'
RSpec.describe "/posts", type: :request do
describe "when user is not allowed" do
let(:user_not_allowed) { create(:user, admin: false, editor: false) }
let(:tag) { create(:tag) }
let(:valid_attributes) { attributes_for(:post, tag_id: tag.id) }
before do
sign_in user_not_allowed
end
describe "GET /index" do
it "return code 401" do
diet = Post.create! valid_attributes
get edit_post_url(post)
expect(response).to have_http_status(401)
end
end
end
end
ポリシーのテストも簡単です。責任が1つしかない小さな方法がたくさんあります。
require 'rails_helper'
RSpec.describe PostsCreationPolicy do
describe "when user is not allowed" do
let(:user) { create(:user, editor: false, admin: false) }
let(:user_editor) { create(:user, editor: true, email: verified) }
let(:tag) { create(:tag) }
let(:post) { create(:post, tag_id: tag.id) }
describe ".create?" do
context "when user is allowed" do
it "creates a new post" do
expect(described_class.create?(user_editor, post)).to eq(true)
end
end
context "when user is not allowed" do
it "does not create a new post" do
expected(described_class.create?(user, post)).to eq(false)
end
end
end
# ...more test cases
end
end
すべてのシナリオでオブジェクトの作成が許可されているかどうかをテストします。
ポリシーパターンの概念は小さいですが、大きな結果が得られます。単純または複雑なアクセス許可を処理する必要があるたびに、ポリシーオブジェクトを適用することを検討してください。 RSpecを使用したテストに関しては、データベースレコードを使用する必要はありません。ポリシーは純粋にRubyオブジェクトであり、テストはシンプルかつ高速になります。
-
完全ガイド:Fitbit Pay
Fitbit は、利用可能な最高のスマート ウェアラブルの 1 つです。多くのモデルがあり、多くの機能を備えています。 Fitbit の有名な機能の 1 つに Fitbit Pay があります。 Fitbit Ionic と Fitbit Versa の近距離無線通信チップを使用すると、非接触型決済を利用できるあらゆる店舗で支払うことができます。 この投稿では、Fitbit Pay の使用方法を理解するのに役立つ完全なガイドを掲載しています。 Fitbit Pay とは? Fitbit Pay は、Fitbit Ionic および Versa にデビット カードまたはクレジット カードを追
-
Android のウイルス除去の完全ガイド
あらゆる職業において、ウイルスに感染することは最大の悪夢です! テクノロジーの世界では、ウイルスとマルウェアはデスクトップとラップトップに関連付けられることがよくありますが、おそらく最も影響を受けやすいオペレーティング システムの 1 つは Android スマートフォンです。過去数か月にわたって、数多くのエクスプロイトがありました。研究者は、すべての Android スマートフォンの 87% が少なくとも 1 つの重大な脆弱性にさらされており、デバイスの 95% が単純なテキスト メッセージでハッキングされる可能性があることを発見しました. では、携帯電話がウイルスに感染したらどうしま