130

オプションがapplication_controllerに記載されている場合、protect_from_forgeryログインしてGETリクエストを実行できますが、最初のPOSTリクエストでRailsがセッションをリセットし、ログアウトします.

オプションを一時的にオフにprotect_from_forgeryしていましたが、Angular.js で使用したいと考えています。それを行う方法はありますか?

4

8 に答える 8

277

DOM から CSRF 値を読み取ることは良い解決策ではないと思います。これは単なる回避策です。

angularJS の公式 Web サイトhttp://docs.angularjs.org/api/ng.$httpのドキュメント形式は次の とおりです。

ドメインで実行されている JavaScript のみが Cookie を読み取ることができるため、サーバーは、XHR がドメインで実行されている JavaScript からのものであることを保証できます。

これ (CSRF 保護) を利用するには、サーバーは、最初の HTTP GET 要求で、XSRF-TOKEN と呼ばれる JavaScript 読み取り可能なセッション Cookie にトークンを設定する必要があります。後続の非 GET 要求で、サーバーは Cookie が X-XSRF-TOKEN HTTP ヘッダーと一致することを確認できます。

これらの指示に基づく私の解決策は次のとおりです。

まず、Cookie を設定します。

# app/controllers/application_controller.rb

# Turn on request forgery protection
protect_from_forgery

after_action :set_csrf_cookie

def set_csrf_cookie
  cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end

次に、すべての非 GET リクエストでトークンを検証する必要があります。
Rails はすでに同様のメソッドでビルドされているため、単純にオーバーライドしてロジックを追加できます。

# app/controllers/application_controller.rb

protected
  
  # In Rails 4.2 and above
  def verified_request?
    super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
  end

  # In Rails 4.1 and below
  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end
于 2013-04-02T10:30:34.320 に答える
79

デフォルトの Rails CSRF 保護 ( <%= csrf_meta_tags %>) を使用している場合は、次のように Angular モジュールを構成できます。

myAngularApp.config ["$httpProvider", ($httpProvider) ->
  $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
]

または、CoffeeScript を使用していない場合 (何!?):

myAngularApp.config([
  "$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
  }
]);

必要に応じて、次のような非 GET リクエストでのみヘッダーを送信できます。

myAngularApp.config ["$httpProvider", ($httpProvider) ->
  csrfToken = $('meta[name=csrf-token]').attr('content')
  $httpProvider.defaults.headers.post['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.put['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.patch['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.delete['X-CSRF-Token'] = csrfToken
]

また、クライアントではなくサーバー上のすべてのベースをカバーしているHungYuHei の回答を必ず確認してください。

于 2013-02-06T17:30:36.990 に答える
4

以前のすべての回答をマージする回答であり、Devise認証ジェムを使用していることに依存しています。

まず、gem を追加します。

gem 'angular_rails_csrf'

次に、rescue_fromapplication_controller.rb にブロックを追加します。

protect_from_forgery with: :exception

rescue_from ActionController::InvalidAuthenticityToken do |exception|
  cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
  render text: 'Invalid authenticity token', status: :unprocessable_entity
end

最後に、interceptor モジュールを angular アプリに追加します。

# coffee script
app.factory 'csrfInterceptor', ['$q', '$injector', ($q, $injector) ->
  responseError: (rejection) ->
    if rejection.status == 422 && rejection.data == 'Invalid authenticity token'
        deferred = $q.defer()

        successCallback = (resp) ->
          deferred.resolve(resp)
        errorCallback = (resp) ->
          deferred.reject(resp)

        $http = $http || $injector.get('$http')
        $http(rejection.config).then(successCallback, errorCallback)
        return deferred.promise

    $q.reject(rejection)
]

app.config ($httpProvider) ->
  $httpProvider.interceptors.unshift('csrfInterceptor')
于 2014-05-28T15:53:38.063 に答える
1

これに対する非常に簡単なハックを見つけました。私がしなければならなかったのは次のことだけです:

a. 私の見解で$scopeは、トークンを含む変数を初期化します。たとえば、フォームの前に、またはコントローラーの初期化でさらに良くします。

<div ng-controller="MyCtrl" ng-init="authenticity_token = '<%= form_authenticity_token %>'">

b. AngularJS コントローラーで、新しいエントリを保存する前に、トークンをハッシュに追加します。

$scope.addEntry = ->
    $scope.newEntry.authenticity_token = $scope.authenticity_token 
    entry = Entry.save($scope.newEntry)
    $scope.entries.push(entry)
    $scope.newEntry = {}

これ以上何もする必要はありません。

于 2014-12-30T22:21:47.463 に答える