Heimdallr:モデルフィールド保護と新しいCanCan

ほとんどのWebプロジェクトをブラウザベースのアプリケーションに変える過程で、多くの疑問が生じます。 そしてそれらの最も重要なものの1つは、不必要なコードなしでアクセス権を処理することです。 このトピックに関する反省が大きな問題につながりました。ActiveRecord( Egor 、hello !;)のモデルのフィールドレベルで保護を実装する便利な方法はありません。 CanCanはコントローラーレベルで制限を追加しますが、これはすべての問題を解決するにはレベルが高すぎます。



少しフラストレーションを感じた後、2つのかわいい宝石を書きました。 Heimdallr (Heimdal)とその拡張版Heimdallr :: Resourceをご覧ください 。 彼らはあなたのモデルに平和と安全をもたらします。



ハイムダル



最初に問題を詳しく見てみましょう。 プロジェクトの大部分は、セキュリティとRESTコントローラーのアクセス制御を実際に同一視しています。 大規模なプロジェクトでは、コードを複製しないように、多くの場合モデルに移行します。 そして、コントローラー内のアクションの数が耐えられないほど大きくならないように、アクセスフィールドを制御するためにダウンすることがあります。







多くのRESTfulアプリケーションでは、第1レベルと第2レベルは同じです。 したがって、最終的には次のようになります。



  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は本当に時代であり、それでもまだうまくいきます。 しかし、彼にはいくつかの問題があります。





モデル制御ツールとしてHeimdallrの開発を開始しましたが、実際には、コントローラーを制限するのに十分なデータがあることが判明しました。 そのため、Heimdallr :: Resourceを作成しました。



Heimdallrのこの部分は、できる限りCanCanを模倣しています。 同じload_and_authorize



フィルターがあり、これがどのように機能するかです:





次のようになります。



 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があります。 アクセス権は次の質問をします。



  1. インデックスを通じてどのエンティティを取得できますか?
  2. どちらを変更できますか?
  3. どれを削除できますか?
  4. 新しいエンティティを作成できますか?
  5. 更新時にどのフィールドを設定できますか?
  6. 作成時にどのフィールドを設定できますか?


最初の質問は、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に特別な魔法を与えることです。 コミヤコフがあなたを見ていることを忘れないでください!



ಠ_ಠ



All Articles