少しフラストレーションを感じた後、2つのかわいい宝石を書きました。 Heimdallr (Heimdal)とその拡張版Heimdallr :: Resourceをご覧ください 。 彼らはあなたのモデルに平和と安全をもたらします。
ハイムダル
最初に問題を詳しく見てみましょう。 プロジェクトの大部分は、セキュリティとRESTコントローラーのアクセス制御を実際に同一視しています。 大規模なプロジェクトでは、コードを複製しないように、多くの場合モデルに移行します。 そして、コントローラー内のアクションの数が耐えられないほど大きくならないように、アクセスフィールドを制御するためにダウンすることがあります。
多くのRESTfulアプリケーションでは、第1レベルと第2レベルは同じです。 したがって、最終的には次のようになります。
- モデルアクセス
- モデルフィールドへのアクセス
同時に、プロジェクトへのアクセスに伴い、フィールドへのアクセスを管理する重要性は急速に高まっています。 そして、最近のGithubの信用低下の例は、Fieldsの影響の最も良い例ですか? しかし、だれがそれを必要とします!」
以下は、Heimdallrがこれをどのように支援できるかの例です。
class Article < ActiveRecord::Base include Heimdallr::Model belongs_to :owner, :class_name => 'User' restrict do |user, record| if user.admin? # scope :fetch scope :delete can [:view, :create, :update] else # - scope :fetch, -> { where('owner_id = ? or secrecy_level < ?', user.id, 5) } scope :delete, -> { where('owner_id = ?', user.id) } # ... # ( )... if record.try(:owner) == user can :view can :update, { secrecy_level: { inclusion: { in: 0..4 } } } else can :view cannot :view, [:secrecy_level] end # ... , . can :create, %w(content) can :create, { owner_id: user.id, secrecy_level: { inclusion: { in: 0..4 } } } end end end
モデル内部の単純なDSLを使用して、モデル自体とそのフィールドへのアクセスの両方の制限を宣言します。 Heimdallrは、
.restrict
メソッドを使用してモデルを拡張します。 このメソッドを呼び出すと、完全に透過的に使用できるプロキシラッパーでモデルクラスがラップされます。
Article.restrict(current_user).where(:typical => true)
Class.restrict
呼び出しでは、ブロックの2番目のパラメーターはnilであることに注意してください。 したがって、現在のオブジェクトのフィールドの状態に依存するすべてのチェックは、
.try(:field)
でラップする必要があります。
これらの制限は、コントローラだけでなく、どこでもプロジェクトで使用できます。 そしてこれは重要です。 保護フィールドを読み取ろうとすると、例外が発生します。 このような動作は予測可能ですが、ビューの設計にはあまり便利ではありません。
ビューに関する問題を解決するために、Heimdallrは明示的と暗黙的の2つの戦略を実装しています。 デフォルトでは、Heimdallrは明示的な動作モデルに従います。 そして、これは別の動作です:
article = Article.restrict(current_user).first @article = article.implicit @article.protected_thing # => nil
わかった 記事の冒頭で、CanCanについて言及しました。 しかし、彼は根本的に異なる方法で問題を解決しませんか?
カンカン
多くのRailsプロジェクトでは、「セキュリティ」という用語はCanCan gemの同義語です。 CanCanは本当に時代であり、それでもまだうまくいきます。 しかし、彼にはいくつかの問題があります。
- CanCanは、モデルで動作しないツールとして考えられていました。 RESTコントローラーが保護されるアーキテクチャを提供し、攻撃者は単にモデルに到達しません。 この戦略は良い場合もあれば、そうでない場合もあります。 しかし、実際には、どんなに一生懸命努力してもフィールドに行くことはできません。 CanCanは単にフィールドについて何も知らず、何も知ることができません。
- Branch 1.xは死んでおり、サポートされていません。 いくつかの不快なバグがあり、namespacsを使用した困難なケースでは動作しません。 ブランチ2.xは非常に長く開発されています。
モデル制御ツールとしてHeimdallrの開発を開始しましたが、実際には、コントローラーを制限するのに十分なデータがあることが判明しました。 そのため、Heimdallr :: Resourceを作成しました。
Heimdallrのこの部分は、できる限りCanCanを模倣しています。 同じ
load_and_authorize
フィルターがあり、これがどのように機能するかです:
- scope:createが現在のコンテキストに対して宣言されていない(したがって、エンティティを作成できない)場合、newおよびcreate
- scope:updateがない場合は、編集も更新もできません。
- スコープの同様のアプローチ:destroy
- 実際には、すぐに保護されたエンティティを取得するため、手動で
restrict
を呼び出すことを忘れないでください
次のようになります。
class ArticlesController < ApplicationController include Heimdallr::Resource load_and_authorize_resource # : # # load_and_authorize_resource :resource => :article # : # # routes.rb: # resources :categories do # resources :articles # end # # load_and_authorize_resource :through => :category def index # @articles restrict' end def create # @article restrict' end end
REST APIプロバイダー
ストーリーの冒頭で、アイデアの根源であるクライアントアプリケーションとサーバーREST-API間のアクセス権の同期について説明しました。 それで、私たちはどのような慣習になったのでしょうか。
クライアントJSアプリケーションとして実装する必要があるロールを備えたシンプルなCRUDインターフェースがあると想像してください。 この場合、サーバー上には、インデックス/作成/更新/破棄を伴うRESTがあります。 アクセス権は次の質問をします。
- インデックスを通じてどのエンティティを取得できますか?
- どちらを変更できますか?
- どれを削除できますか?
- 新しいエンティティを作成できますか?
- 更新時にどのフィールドを設定できますか?
- 作成時にどのフィールドを設定できますか?
最初の質問は、Heimdallrによって本質的に決定されます。 目的のスコープとすべてを決定しました。 誰も余分なものを見ません。 残りについて。 前回の記事で、RESTプロバイダーのJSON表現をレンダリングする方法について説明しました。 同じ手法を使用すると、次のフィールドを使用してビューを非常に簡単に拡張できます。
{modifiable: self.modifiable?, destroyable: self.destroyable?}
作成できますか? そして、どの分野で?
REST APIの場合、新しいメソッドはほとんど役に立ちません。 そして、これは、私たちが何かを正確に作成できるかどうかを判断するのに最適な場所です。 たとえば、次のように:
Article.restrictions(current_user).allowed_fields[:create]
まったく作成できない場合、Heimdallr :: Resourceはこのリクエストにエラーで応答します。 それ以外の場合、入力可能なフィールドのリストを取得します。
.creatable?
は
.creatable?
メソッドも宣言してい
.creatable?
、RESTを介してスローできるようにします。
更新できますか?
アイデアは創造に似ています。 今回のみ、編集メソッドを宣言します。
Article.restrictions(current_user).allowed_fields[:update]
結論として
Heimdallとその拡張機能であるHeimdallr :: Resourceを使用すると、コードに不要なゴミがなくてもアクセス権を簡単に管理できます。 そして、重要なことは、REST-APIに特別な魔法を与えることです。 コミヤコフがあなたを見ていることを忘れないでください!
ಠ_ಠ