Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

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オブジェクトであり、テストはシンプルかつ高速になります。


  1. 完全ガイド:Fitbit Pay

    Fitbit は、利用可能な最高のスマート ウェアラブルの 1 つです。多くのモデルがあり、多くの機能を備えています。 Fitbit の有名な機能の 1 つに Fitbit Pay があります。 Fitbit Ionic と Fitbit Versa の近距離無線通信チップを使用すると、非接触型決済を利用できるあらゆる店舗で支払うことができます。 この投稿では、Fitbit Pay の使用方法を理解するのに役立つ完全なガイドを掲載しています。 Fitbit Pay とは? Fitbit Pay は、Fitbit Ionic および Versa にデビット カードまたはクレジット カードを追

  2. Android のウイルス除去の完全ガイド

    あらゆる職業において、ウイルスに感染することは最大の悪夢です! テクノロジーの世界では、ウイルスとマルウェアはデスクトップとラップトップに関連付けられることがよくありますが、おそらく最も影響を受けやすいオペレーティング システムの 1 つは Android スマートフォンです。過去数か月にわたって、数多くのエクスプロイトがありました。研究者は、すべての Android スマートフォンの 87% が少なくとも 1 つの重大な脆弱性にさらされており、デバイスの 95% が単純なテキスト メッセージでハッキングされる可能性があることを発見しました. では、携帯電話がウイルスに感染したらどうしま