Ruby 認証をマスターする:評論家 vs. CanCanCan
現在、多くの Web アプリケーションには、ホームページなどの一般に公開されているページと、ユーザーがアクセスするためにログインする必要があるより安全なページが搭載されています。ユーザー登録、ログイン、ユーザー セッション状態の追跡のプロセスは「認証」と呼ばれます。
同時に、ログインしたユーザーを扱うときは、ユーザーの役割に応じて、ユーザーが利用できるアクションとリソースを分ける必要があります。たとえば、「管理者」は通常、通常のユーザーよりも多くのアクセス権を持っています。認証されたユーザー アクセスを分離するこのプロセスは、「認可」と呼ばれます。
この投稿では、これまでのところ Ruby で最も人気のある 2 つの認可ライブラリ、Pundit と CanCanCan について検討します。
さあ、飛び込んでみましょう!
セットアップと前提条件
この記事では、ユーザーと投稿を特徴とするシンプルな Rails 7 アプリを使用します。ユーザーには「編集者」または「ライター」の役割が割り当てられます。このようなシナリオは、認可がどのように機能するかを示すのに最適です。
以下のサンプル アプリのコード リポジトリを確認してください。
- 評論家
- カンカンカン
この記事は認可に焦点を当てていますが、付随する主題である認証を無視することはできません。
認証の設定の詳細については、この投稿の範囲外であるため説明しません。 Devise gem ドキュメントのインストール手順に従ってください (Devise と認証 gem を組み合わせます)。
もう 1 つ — Pundit を扱うか CanCanCan を扱うかに関係なく、アプリのユーザー ロールを定義する実際の作業は、どちらの認可 gem をインストールしても自動的には行われません。手動で設定する必要があります。
そうしましょう。
ユーザーの役割の定義
すでに Devise gem をインストールし、ユーザー モデルをセットアップしていると仮定します。次のステップは、アプリのユーザーにどのような役割を与えるかを決定することです。私たちの場合、次の役割を設定します。
- ライター - このユーザー役割は作成できるようになります。 、編集 、更新 、削除します。 自分たちの投稿。同時に、 ライターは閲覧することもできます。 他のライターの投稿
- 編集者 - 編集者の役割を持つユーザーは編集できます。 、更新 、表示します。 、削除します。 ユーザーの投稿は可能ですが、作成することはできません。 自分自身の投稿
ユーザーのロールを保存する列を追加します (移行を使用してユーザーのテーブルを変更します)。
次に、移行を実行します。
次に、定義したロールを含めるようにユーザー モデルを変更します。
これを進めている間に、Post をセットアップしましょう。 title の属性を持つモデル と body 、および投稿を書いたユーザーへの参照:
外部キー user_id を追加します。 Post に 作成されたすべての投稿を特定のユーザーに関連付けるモデル。 Devise を使用してユーザー認証をすでに設定しているため、Posts の create メソッドを変更するだけで済みます。 コントローラでuser_idを自動的に設定します 現在ログインしているユーザーへ:
ユーザー モデルを変更して、Post に関連付けることもできます。 モデル:
最後に、それぞれが異なるロールを持ついくつかのユーザーをデータベースにシードしましょう:
次に、データベースをシードします。
これまでのところ、アプリには次のものがあります:
- Devise を使用して設定された認証。
- 「ライター」と「編集者」という 2 つのユーザー役割が定義されています。
- A
Postモデル。
これで、Pundit と適切に連携するために必要なものがすべて揃いました。
Pundit による Ruby アプリの承認
Pundit は、オブジェクト指向アーキテクチャとプレーンな Ruby クラスを中心に構築された認可ライブラリです。これにより、アプリに合わせて拡張できる強固な認証レイヤーを構築するためのツールが提供されます。
Ruby アプリに Pundit をインストールする
gem をアプリの Gemfile に追加します。
次に、ターミナルで次のコマンドを実行します。
あるいは、次のコマンドを実行します。
認可は主にコントローラ リソースへのアクセスの許可または拒否を扱うため、次のステップは Pundit の認可モジュールをアプリケーション コントローラに追加することです。
最後に、他のすべてのポリシーが継承する基本ポリシー クラスを生成します。
これにより、次の基本ポリシー クラスが得られます。
これで、Pundit は適切にセットアップされ、使用できるようになりました。さらに、認証とユーザーの役割が設定されています。
次に、ポリシーを使用して、各ユーザー ロールが Post にアクセスする方法を定義するルールを実装しましょう。 リソース。
評論家ポリシーの構成
Pundit の専門用語では、「ポリシー」は、ユーザー ロールがさまざまなリソースとどのように対話するかに関するすべてのルールを定義する単純な Ruby クラスです。
これらのポリシーには、いくつかの注目すべき機能が備わっています。
- 各ポリシーは、既存のモデルにちなんで「Policy」という単語を接尾辞として付けられます。たとえば、
Postをどのように実行するかを定義するポリシーです。 アクセスされるモデルはPostPolicyと呼ばれます . attr_reader:これは 2 つの引数を取ります。最初の引数はuserです。 、具体的には、現在ログインしているユーザー —current_user— そして 2 番目の引数は、認可ルールを定義するモデルです。この場合、postです。 .- 認可ルールが設定されているリソースのコントローラー メソッドにマップされるクエリ メソッド。組織上の目的から、すべてのポリシーを
app/policiesの下に置くことが最善です。 フォルダ。
アプリ内のさまざまなユーザー ロールに対してどのようなアクセス ルールを定義する必要があるかはわかっているので、ライター ロールから始めましょう。
役割の評論家ポリシーの定義
Writer ロールを使用して、これがどのように行われるかを見てみましょう。まず、ライター ロールの Post へのアクセスの概要を説明します。 リソースは次のようになります:
- 作成 自分の投稿
- 編集と更新 自分の投稿
- 表示 (または読み取り) 自分の投稿と他のユーザーの投稿
- 削除 自分の投稿
これを念頭に置いて、投稿へのアクセス方法を制御する新しいポリシーを生成してください。
これにより、前に生成した基本ポリシーを継承する次の汎用ポリシー クラスが得られます。
それに応じて、ライター ロールのアクセス ルールを追加しましょう (これらは、基本ポリシー クラスから継承されたルールもオーバーライドします)。
ここでは、投稿のコントローラーでの対応するアクションである投稿の作成、編集、更新、削除時にライターができることを定義します。お気づきかと思いますが、これらのルールは投稿一般に適用され、必ずしもライター自身の投稿に適用されるわけではありません (スコープに関するセクションで説明します)。
ここでは、このポリシーをどのように使用できるかを見てみましょう。
Pundit でのポリシーの使用
ポリシーを使用するには、Pundit の authorize に電話してください。 アクセス ルールを確認するコントローラーのメソッドのメソッド。関連するポリシー クラス、より具体的には、authorize の場所に基づいて呼び出されるアクションをインスタンス化します。 メソッドが呼び出されました。
たとえば、authorize を呼び出してみましょう。 ポストコントローラーの作成で メソッド:
これをテストするには、編集者としてログインし、create を試してください。 ポスト。これを実行すると、次のエラーが発生します。

これで目的は達成できますが、このようなエラー ページを表示するのはユーザー エクスペリエンスにとって良くありません。次のセクションでは、NotAuthorizedError を救出する方法を学びます。 よりユーザーフレンドリーなものを提供してください。
評論家のNotAuthorizedErrorから救出する
まず、ApplicationController を編集する必要があります。 次のように:
ここでは基本的に、Pundit に user_not_authorized を使用するように指示しています。 NotAuthorizedError の場合は必ずメソッド 上げられる。権限のないユーザーを特定のページにリダイレクトするだけで、何が起こったかを説明する関連するフラッシュ メッセージも表示されます。

これで、非常に一般化された権限ケースを処理できるシンプルな権限システムが完成しました。
しかし、よりきめ細かい権限が必要な場合はどうすればよいでしょうか?このためには、Pundit のスコープを利用する必要があります。
専門家の範囲
Pundit スコープは ActiveRecord スコープに似ています。後者では、スコープを使用して、特定の基準に従ってレコードをフェッチできます。ただし、Pundit のスコープを使用すると、設定した特定のルールに従って特定のリソースへのアクセスを管理できます。
編集者が「下書き」ステータスにある投稿を表示および編集できるようにすると同時に、ライターが自分に属する投稿のみを作成、表示、編集、更新、削除できるようにしたいとします。
まず、投稿ポリシーを次のように編集します。
次に、次のように、投稿コントローラー内のリソースへのアクセスを承認します。
もちろん、Pundit を使用した調査は、ここで示したものよりもさらに深くなる可能性がありますが、この投稿ではそれをそのままにしておきます。必要に応じて、Pundit のドキュメントを参照して、より高度な方法でスコープを使用する方法を確認してください。
ここでは、Rails の強力なパラメータを使用してライブラリを使用する方法を見てみましょう。
Rails の強力なパラメータで Pundit を使用する
Pundit の認可ルールと Rails の強力なパラメータを組み合わせることで、リソースの属性へのロックダウン アクセスを実現できます。たとえばエディタが必要だとします。 Post の抜粋フィールドにアクセスできる唯一のユーザーであること モデル。どうしますか?
まず、適切な名前のブロックを関連ポリシーに追加します。
次に、コントローラ内の許可された params ブロックを変更します。
これで抜粋が作成されました。 属性は編集者のみが使用できます。
次に、もう 1 つの認可ライブラリである CanCanCan を見てみましょう。
Ruby アプリ用の CanCanCan の紹介
CanCanCan は、「能力」クラスを使用して、誰が Rails アプリの何にアクセスできるかを定義する認可ライブラリです。実際のアクセス制御は、認可モジュールとさまざまなビュー ヘルパーを使用して実現されます。
CanCanCan のインストール
インストールは、以下のコマンドを実行するだけで簡単です。
Pundit と同様に、CanCanCan を使用すると、「能力」クラスと呼ばれるプレーンな Ruby クラス オブジェクト内ですべてのアクセス ルールを定義できます。次に、次のジェネレーター コマンドを使用してこれを実行しましょう。
これにより、以下のクラス オブジェクトが生成されます。
次に、能力クラスがサンプル Rails アプリのアクセス ルールを定義する方法について詳しく学びましょう。
CanCanCan アビリティの定義と確認
Pundit の例と同じユーザー ロール (ライターと編集者) を使用します。ライターは自分の投稿を作成、編集、更新、破棄したり、他のライターの投稿を表示したりできます。編集者は、独自の投稿を作成すること以外はすべて行うことができます。
CanCanCan を使用するには、まず、各ユーザーまたはロールが能力クラスでアクセスできる内容を次の形式に従って定義します。
例として:
次に、コントローラーで、特定のアクションにアクセス ルールが存在するかどうかを確認します。この例では、edit を使用します。 アクション:
これを設定した状態で、別のライターとして編集投稿ビューにアクセスすると、以下のエラーが表示されます。

そして、Pundit で行ったように、このエラーを解決して、より適切なエラー ページをユーザーに表示しましょう。
CanCanCan の「アクセス拒否」エラーの処理
リソースが承認されていない場合、CanCanCan は CanCan::AccessDenied を生成します。 エラー。この例外をキャッチする最も簡単な方法は、ApplicationController を変更することです。 次のように:
これを行うと、優れたユーザー エクスペリエンスが得られます。以下のスクリーンショットでは、権限のないユーザーがホームページにリダイレクトされ、関連するフラッシュ メッセージが表示されます。

ユーザーに表示されるエラー メッセージをカスタマイズすることもできます。
アプリが XML を応答として提供する場合、または単に CanCanCan::AccessDenied の処理を詳しく知りたい場合 例外として、CanCanCan のドキュメントを確認してください。ここでは、CanCanCan のさまざまな機能を組み合わせて、より堅牢な認証レイヤーを作成する方法を見てみましょう。
複数の CanCanCan アビリティを組み合わせる
能力クラスのリソースに対して複数のアクセス ルールを定義できます。たとえば、ライターと編集者の役割を考えると、次のことができます。
問題は、なぜこれを行う必要があるのかということです。
CanCanCan を使用すると、すべてのアクセス ルールを 1 つのアビリティ ファイルで定義できます。これには長所と短所の両方があります。
すべてのルールが 1 か所で定義されているため、すべてのルールを 1 か所にまとめておくと、アクセス ルールを処理するのに非常に便利です。
ただし、アプリが多くのユーザー ロールを処理する場合、または承認が必要なリソースが複数ある場合、アビリティ クラスが大きくなりすぎて複雑になりすぎて処理できなくなる可能性があります。これに対処する 1 つの方法は、次のようにメソッド定義を使用できるようにアビリティ クラスを再編成することです。
CanCanCan には、この記事では十分にカバーしきれないほど多くの機能があります。詳細については、CanCanCan の詳細なドキュメントを参照してください。
最後に、各ライブラリの機能について簡単に触れ、一方を選択する理由を説明しましょう。
機能の比較:Ruby アプリの評論家と CanCanCan の比較
- ファイル構成 - Pundit を使用すると、複数のポリシー ファイルにわたるアプリの承認を簡単に整理できます。しかし、CanCanCan では、認可ルールは 1 つのアビリティ ファイル内に存在します。複数のアビリティ ファイルを操作することは引き続き可能ですが、これはデフォルトの実装スタイルではありません。
- テスト - Pundit の複数の能力クラスと比較して、権限コードはほとんどが 1 つのクラス内に存在するため、CanCanCan のテストの作成は Pundit よりも簡単になる可能性があります。
- ヘルパー - どちらのライブラリも、ビュー レイヤーの権限をチェックするための多数のビュー ヘルパーを提供します。 CanCanCan は
can?を提供します Pundit はpolicyを使用して比較的類似した機能を提供します。 ヘルパー。 - デバイスの統合 - この記事で使用した例からわかるように、両方のライブラリは Devise と非常によく統合されています。
まとめ
この記事では、Ruby と Rails エコシステムで最も人気のある 2 つの認可 gem、Pundit と CanCanCan について検討しました。
どちらのライブラリも、Rails アプリの権限を管理するための豊富な機能セットを提供します。このため、どちらの gem を選択すればよいかを判断することはほぼ不可能です。どちらの gem も、最も複雑な権限設定も管理できます。
アプリで Pundit と CanCanCan を試して、どちらがニーズに最も適しているかを確認することをお勧めします。
コーディングを楽しんでください!
追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。
-
Ruby内部:Rubyオブジェクトのメモリレイアウトの調査
Ruby内部のクイックツアーをご希望ですか? その後、あなたは御馳走になります。 なぜなら … Rubyオブジェクトがメモリ内にどのように配置されるか、そして内部データ構造を操作していくつかのクールなことを行う方法を一緒に探求します。 シートベルトを締めて、Rubyインタープリターの奥深くへの旅の準備をしてください! アレイのメモリレイアウト 配列を作成するとき、Rubyはそれをシステムメモリと少しのメタデータでバックアップする必要があります。 メタデータに含まれるもの : 配列サイズ(アイテム数) アレイ容量 クラス オブジェクトのステータス(凍結されているかどうか) データが
-
Ruby on Rails の説明:強力な Web 開発フレームワーク
Web 開発テクノロジの研究に時間を費やしたことがある人なら、Ruby on Rails と呼ばれるものに出会ったことがあるかもしれません。このテクノロジーは、HTML や CSS などの言語と同じカテゴリで議論されることがよくありますが、興味深いことに、Ruby on Rails はプログラミング言語ではなく、Web 開発フレームワークです。 Ruby on Rails とは何なのか、またどのように機能するのか疑問に思われるかもしれません。この記事では、Ruby と Ruby on Rails の基本を詳しく説明します。次に、なぜこのプログラミング テクノロジーがここ数年でこれほど注目