복붙노트

[RUBY-ON-RAILS] RegistrationsController #에서 ActionController :: InvalidAuthenticityToken 작성

RUBY-ON-RAILS

RegistrationsController #에서 ActionController :: InvalidAuthenticityToken 작성

내 사용자 인증을 위해 고안를 사용하고 안녕 갑자기 나의 새로운 사용자 등록이 작동되지 않았습니다.

이것은 내가 점점 오전 오류였다.

ActionController::InvalidAuthenticityToken

Rails.root: /home/example/app
Application Trace | Framework Trace | Full Trace

Request

Parameters:

{"utf8"=>"✓",
 "user"=>{"email"=>"example@gmail.com",
 "password"=>"[FILTERED]",
 "password_confirmation"=>"[FILTERED]"},
 "x"=>"0",
 "y"=>"0"}

이 내 등록 컨트롤러

class RegistrationsController < Devise::RegistrationsController
  prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
  prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]

  before_filter :configure_permitted_parameters

  prepend_view_path 'app/views/devise'

  # GET /resource/sign_up
  def new
    build_resource({})
    respond_with self.resource
  end

  # POST /resource
  def create
    build_resource(sign_up_params)

    if resource.save
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_navigational_format?
        sign_up(resource_name, resource)
        respond_with resource, :location => after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
        expire_session_data_after_sign_in!
        respond_with resource, :location => after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource

      respond_to do |format|
        format.json { render :json => resource.errors, :status => :unprocessable_entity }
        format.html { respond_with resource }
      end
    end
  end

  # GET /resource/edit
  def edit
    render :edit
  end

  # PUT /resource
  # We need to use a copy of the resource because we don't want to change
  # the current user in place.
  def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)

    if update_resource(resource, account_update_params)
      if is_navigational_format?
        flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
          :update_needs_confirmation : :updated
        set_flash_message :notice, flash_key
      end
      sign_in resource_name, resource, :bypass => true
      respond_with resource, :location => after_update_path_for(resource)
    else
      clean_up_passwords resource
      respond_with resource
    end
  end

  # DELETE /resource
  def destroy
    resource.destroy
    Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
    set_flash_message :notice, :destroyed if is_navigational_format?
    respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
  end

  # GET /resource/cancel
  # Forces the session data which is usually expired after sign
  # in to be expired now. This is useful if the user wants to
  # cancel oauth signing in/up in the middle of the process,
  # removing all OAuth session data.
  def cancel
    expire_session_data_after_sign_in!
    redirect_to new_registration_path(resource_name)
  end

  protected

  # Custom Fields
  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) do |u|
      u.permit(:first_name, :last_name,
        :email, :password, :password_confirmation)
    end
  end

  def update_needs_confirmation?(resource, previous)
    resource.respond_to?(:pending_reconfirmation?) &&
      resource.pending_reconfirmation? &&
      previous != resource.unconfirmed_email
  end

  # By default we want to require a password checks on update.
  # You can overwrite this method in your own RegistrationsController.
  def update_resource(resource, params)
    resource.update_with_password(params)
  end

  # Build a devise resource passing in the session. Useful to move
  # temporary session data to the newly created user.
  def build_resource(hash=nil)
    self.resource = resource_class.new_with_session(hash || {}, session)
  end

  # Signs in a user on sign up. You can overwrite this method in your own
  # RegistrationsController.
  def sign_up(resource_name, resource)
    sign_in(resource_name, resource)
  end

  # The path used after sign up. You need to overwrite this method
  # in your own RegistrationsController.
  def after_sign_up_path_for(resource)
    after_sign_in_path_for(resource)
  end

  # The path used after sign up for inactive accounts. You need to overwrite
  # this method in your own RegistrationsController.
  def after_inactive_sign_up_path_for(resource)
    respond_to?(:root_path) ? root_path : "/"
  end

  # The default url to be used after updating a resource. You need to overwrite
  # this method in your own RegistrationsController.
  def after_update_path_for(resource)
    signed_in_root_path(resource)
  end

  # Authenticates the current scope and gets the current resource from the session.
  def authenticate_scope!
    send(:"authenticate_#{resource_name}!", :force => true)
    self.resource = send(:"current_#{resource_name}")
  end

  def sign_up_params
    devise_parameter_sanitizer.sanitize(:sign_up)
  end

  def account_update_params
    devise_parameter_sanitizer.sanitize(:account_update)
  end
end

이것은 내 세션 컨트롤러

class SessionsController < DeviseController
  prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
  prepend_before_filter :allow_params_authentication!, :only => :create
  prepend_before_filter { request.env["devise.skip_timeout"] = true }

  prepend_view_path 'app/views/devise'

  # GET /resource/sign_in
  def new
    self.resource = resource_class.new(sign_in_params)
    clean_up_passwords(resource)
    respond_with(resource, serialize_options(resource))
  end

  # POST /resource/sign_in
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_navigational_format?
    sign_in(resource_name, resource)

    respond_to do |format|
        format.json { render :json => {}, :status => :ok }
        format.html { respond_with resource, :location => after_sign_in_path_for(resource) } 
    end
  end

  # DELETE /resource/sign_out
  def destroy
    redirect_path = after_sign_out_path_for(resource_name)
    signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
    set_flash_message :notice, :signed_out if signed_out && is_navigational_format?

    # We actually need to hardcode this as Rails default responder doesn't
    # support returning empty response on GET request
    respond_to do |format|
      format.all { head :no_content }
      format.any(*navigational_formats) { redirect_to redirect_path }
    end
  end


  protected

  def sign_in_params
    devise_parameter_sanitizer.sanitize(:sign_in)
  end

  def serialize_options(resource)
    methods = resource_class.authentication_keys.dup
    methods = methods.keys if methods.is_a?(Hash)
    methods << :password if resource.respond_to?(:password)
    { :methods => methods, :only => [:password] }
  end

  def auth_options
    { :scope => resource_name, :recall => "#{controller_path}#new" }
  end
end

이것은 등록 형태

<%= form_for(:user, :html => {:id => 'register_form'}, :url => user_registration_path, :remote => :true, :format => :json) do |f| %>

    <div class="name_input_container">
        <div class="name_input_cell">


    <%= f.email_field :email, :placeholder => "email" %>


    <%= f.password_field :password, :placeholder => "password", :title => "8+ characters" %>


    <%= f.password_field :password_confirmation, :placeholder => "confirm password" %>


    <div class="option_buttons">
        <div class="already_registered">
            <%= link_to 'already registered?', '#', :class => 'already_registered', :id => 'already_registered', :view => 'login' %>
        </div>
        <%= image_submit_tag('modals/account/register_submit.png', :class => 'go') %>
        <div class="clear"></div>
    </div>
<% end %>

해결법

  1. ==============================

    1.다음과 핵심 application_controller.rb, 세트 protect_from_forgery의 주석 별 :

    다음과 핵심 application_controller.rb, 세트 protect_from_forgery의 주석 별 :

    protect_from_forgery with: :null_session
    

    또한, 워드 프로세서 당, 단순히없이 protect_from_forgery를 선언 : 인수와 함께 사용됩니다 null_session를 기본적으로 :

    protect_from_forgery # Same as above
    

    최신 정보:

    이 유증의 동작에 문서화 된 버그 것 같다. 유증의 저자는이 예외를 발생있어 특정 컨트롤러 액션에 protect_from_forgery을 사용하지 않도록 제안 :

    # app/controllers/users/registrations_controller.rb
    class RegistrationsController < Devise::RegistrationsController
      skip_before_filter :verify_authenticity_token, :only => :create
    end
    
  2. ==============================

    2.당신은 당신의 레이아웃 파일 내부에 <% = csrf_meta_tags %>를 추가하는 것을 잊었다했다.

    당신은 당신의 레이아웃 파일 내부에 <% = csrf_meta_tags %>를 추가하는 것을 잊었다했다.

    예 :. :

    <!DOCTYPE html>
    <html>
    <head>
    <title>Sample</title>
    <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
    </head>
    <body>
    
    <%= yield %>
    
    </body>
    </html>
    
  3. ==============================

    3.TLDR는 : XHR를 통해 양식을 제출하기 때문에 당신은 아마이 문제를보고있다.

    TLDR는 : XHR를 통해 양식을 제출하기 때문에 당신은 아마이 문제를보고있다.

    처음 몇 가지 :

    A는 전체 페이지 새로 고침의 원인이됩니다에 서명 표준 HTTP 늪지, 그리고 이전 CSRF 토큰을 플러시하고 로그인 할 때 레일이 작성하는 하나의 새로운 브랜드로 교체 될 것입니다.

    지금 무효 인 피 각질의 오래된, 오래된 CSRF 토큰이 여전히 페이지에 존재하므로에서 AJAX 기호는 페이지를 새로 고침하지 않습니다.

    이 솔루션은 수동으로 AJAX 로그인 후 HEAD 태그 내부의 CSRF 토큰을 업데이트하는 것입니다.

    내가 뻔뻔하게이 문제에 도움이 스레드에서 빌린 것으로 일부 단계.

    1 단계 : 추가 새로운 CSRF 토큰 성공적으로 로그인 한 후 전송 된 응답 헤더에

    class SessionsController < Devise::SessionsController
    
      after_action :set_csrf_headers, only: :create
    
      # ...
    
      protected
        def set_csrf_headers
          if request.xhr?
            # Add the newly created csrf token to the page headers
            # These values are sent on 1 request only
            response.headers['X-CSRF-Token'] = "#{form_authenticity_token}"
            response.headers['X-CSRF-Param'] = "#{request_forgery_protection_token}"
          end
        end
      end
    

    2 단계 : 사용 jQuery를 새로운 값들이 ajaxComplete 이벤트가 발생하여 페이지를 업데이트합니다 :

    $(document).on("ajaxComplete", function(event, xhr, settings) {
      var csrf_param = xhr.getResponseHeader('X-CSRF-Param');
      var csrf_token = xhr.getResponseHeader('X-CSRF-Token');
    
      if (csrf_param) {
        $('meta[name="csrf-param"]').attr('content', csrf_param);
      }
      if (csrf_token) {
        $('meta[name="csrf-token"]').attr('content', csrf_token);
      }
    });
    

    이게 다예요. YMMV은 고안의 구성에 따라 달라집니다. 이 문제는 궁극적으로 이전 요청을 죽이고 토큰 CSRF, 난간에서 예외가 발생한다는 사실로 인해 발생하는 불구하고 나는 생각한다.

  4. ==============================

    4.당신은 그냥 API를 사용하는 경우 당신은 시도해야합니다 :

    당신은 그냥 API를 사용하는 경우 당신은 시도해야합니다 :

    class ApplicationController < ActionController::Base
      protect_from_forgery unless: -> { request.format.json? }
    end
    

    http://edgeapi.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html#method-i-protect_against_forgery-3F

  5. ==============================

    5.레일 5의 경우는 protect_from_forgery하고 before_actions가 트리거되는 순서에 따른 수 있습니다.

    레일 5의 경우는 protect_from_forgery하고 before_actions가 트리거되는 순서에 따른 수 있습니다.

    : 예외는 before_action의 여전히 방해 하였다와 ApplicationController의 첫 번째 행이었다 내가 가진 protect_from_forgery에도 불구하고, 최근 비슷한 상황에 직면했다.

    이 솔루션은 변화했다 :

    protect_from_forgery with: :exception
    

    에:

    protect_from_forgery prepend: true, with: :exception
    

    그것에 대해 블로그 게시물 거기 여기 http://blog.bigbinary.com/2016/04/06/rails-5-default-protect-from-forgery-prepend-false.html

  6. ==============================

    6.당신은 사용자 인증에 대한 작업 전에 protect_from_forgery의 권리를 넣어해야합니다. 이 적합한 솔루션입니다

    당신은 사용자 인증에 대한 작업 전에 protect_from_forgery의 권리를 넣어해야합니다. 이 적합한 솔루션입니다

    class ApplicationController < ActionController::Base
      protect_from_forgery with: :exception
      before_action :authenticate_user!
    end
    
  7. ==============================

    7.난 경우 누군가 여기를 공유해야한다고 생각 때문에 5.2 또는 6에 레일을 업데이트 할 때 그냥이 디버깅 전체 아침 유사한 문제에 직면 보냈다.

    난 경우 누군가 여기를 공유해야한다고 생각 때문에 5.2 또는 6에 레일을 업데이트 할 때 그냥이 디버깅 전체 아침 유사한 문제에 직면 보냈다.

    나는이 문제가 있었다

    1) CSRF에게 토큰 진위를 확인할 수 없습니다.

    그리고, 추가 건너 뛰는 검증 한 후,

    2) 요청을 통해 갈 것이라고하지만 사용자가 아직 로그인하지 않았습니다.

    내가 개발에 캐싱되지 않았다

      if Rails.root.join('tmp', 'caching-dev.txt').exist?
        config.action_controller.perform_caching = true
        config.action_controller.enable_fragment_cache_logging = true
    
        config.cache_store = :memory_store
        config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" }
      else
        config.action_controller.perform_caching = false
    
        config.cache_store = :null_store
      end
    

    그리고 session_store에서

    config.session_store :cache_store,  servers: ... 
    
    
    

    이 로그인하지 그래서 I의 실행 된 후 - 나는 응용 프로그램은 캐시에 저장 세션려고 같아요,하지만 null입니다.

    bin/rails dev:cache
    

    캐시 시작한 - 로그인 작업을 시작했다.

    당신은해야 할 수도 있습니다

  8. from https://stackoverflow.com/questions/20875591/actioncontrollerinvalidauthenticitytoken-in-registrationscontrollercreate by cc-by-sa and MIT license