दिलचस्प पोस्ट
स्थिर HTML के साथ सामान्य हेडर / पाद लेख क्लोनिंग से पहले गिथूब रेपो का आकार देखें? HitTest का उपयोग करके अपने पर्यवेक्षण के फ्रेम के बाहर एक सबव्यू पर छूने पर छूए: साथएवेंट: रीडर / राइटर ताले में सी ++ पायथन + जेगेज पेज रीडायरेक्ट स्ट्रिंग को द्विआधारी में कनवर्ट करें, फिर पीएचपी का उपयोग कर वापस हास्केल में फिबोनैचि संख्याएं जेनरेट कर रही हैं? मैं PHP के साथ एक सर्वर पोर्ट कैसे पिंग कर सकता हूं? स्क्रिप्ट / उपकरण को सी / सी ++ स्रोत कोड सरणी में बदलने के लिए वैकल्पिक पैरामीटर? HTML और सीएसएस के साथ तालिका स्क्रॉल .myd, .myi, .frm फ़ाइलों से MySQL डाटाबेस कैसे पुनर्प्राप्त करें I कई पंक्तियों पर मूल्य विभाजित करें प्रत्येक डिवाइस के लिए सिक्योर। ANDROID_ID अद्वितीय है? एसएलआर क्वेरी में OR या नहीं का उपयोग करना

पटरियों, प्रमाणीकरण का आश्वासन, सीएसआरएफ मुद्दे

मैं पटरियों का प्रयोग कर एक सिंगल पेज एप्लीकेशन कर रहा हूं। जब साइन इन और बाहर डिवायस नियंत्रकों AJAX का उपयोग कर लागू होते हैं। मुझे जो समस्या आ रही है वह है कि जब 1) साइन इन 2) साइन आउट करें तो फिर से साइन इन करना काम नहीं करता।

मुझे लगता है कि यह सीएसआरएफ टोकन से संबंधित है, जब मैं साइन आउट करता हूं (हालांकि इसे अपैइक नहीं करना चाहिए) और जब से यह एक पृष्ठ है, तब से पुराने सीएसआरएफ टोकन को एक्सहोर अनुरोध में भेजा जा रहा है ताकि सत्र को रीसेट किया जा सके।

अधिक ठोस होने के लिए यह कार्यप्रवाह है:

  1. साइन इन करें
  2. साइन आउट
  3. साइन इन करें (सफल 201. हालांकि WARNING: Can't verify CSRF token authenticity प्रिंट करता है WARNING: Can't verify CSRF token authenticity सर्वर लॉग में WARNING: Can't verify CSRF token authenticity को WARNING: Can't verify CSRF token authenticity )
  4. बाद के अजाक्स अनुरोध 401 अनधिकृत विफल रहता है
  5. वेबसाइट को रीफ्रेश करें (इस समय, पेज हेडर में सीएसआरएफ बदलाव कुछ और में बदलता है)
  6. मैं साइन इन कर सकता हूं, यह काम करता है, जब तक मैं साइन आउट करने और फिर से कोशिश नहीं करता।

कोई सुराग बहुत सराहना की! मुझे बताएं कि क्या मैं और अधिक विवरण जोड़ सकता हूं।

Solutions Collecting From Web of "पटरियों, प्रमाणीकरण का आश्वासन, सीएसआरएफ मुद्दे"

जिम्बो ने एक भयानक काम किया था जिसमें आप जिस समस्या के चलते हैं उसके पीछे "क्यों" समझा जाता है इस मुद्दे को हल करने के लिए आप दो तरीकों को ले सकते हैं:

  1. (जैसा कि Jimbo द्वारा अनुशंसित है) ओवरराइड डिवइस :: सत्रों नियंत्रक को नया सीएसआरएफ टोकन वापस करने के लिए:

     class SessionsController < Devise::SessionsController def destroy # Assumes only JSON requests signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)) render :json => { 'csrfParam' => request_forgery_protection_token, 'csrfToken' => form_authenticity_token } end end 

    और क्लाइंट साइड पर अपने साइन-आउट अनुरोध के लिए एक सफल हेन्डलर बनाएं (संभावित रूप से आपके सेटअप के आधार पर कुछ बदलाव की आवश्यकता होती है, जैसे GET vs DELETE):

     signOut: function() { var params = { dataType: "json", type: "GET", url: this.urlRoot + "/sign_out.json" }; var self = this; return $.ajax(params).done(function(data) { self.set("csrf-token", data.csrfToken); self.unset("user"); }); } 

    यह भी मानता है कि आप सीआरआरएफ टोकन को स्वचालित रूप से सभी AJAX अनुरोधों के साथ इस तरह से कुछ के साथ शामिल कर रहे हैं:

     $(document).ajaxSend(function (e, xhr, options) { xhr.setRequestHeader("X-CSRF-Token", MyApp.session.get("csrf-token")); }); 
  2. अधिक आसानी से, अगर यह आपके आवेदन के लिए उपयुक्त है, तो आप बस skip_before_filter :verify_authenticity_token Devise::SessionsController skip_before_filter :verify_authenticity_token ओवरराइड कर सकते हैं और skip_before_filter :verify_authenticity_token साथ टोकन चेक ओवरराइड कर सकते हैं skip_before_filter :verify_authenticity_token

मैं बस इस समस्या में भी चलाया है। यहां बहुत कुछ चल रहा है

टीएल; डीआर – असफलता का कारण यह है कि सीएसआरएफ टोकन आपके सर्वर सत्र के साथ जुड़ा हुआ है (आपको सर्वर सत्र मिला है या आप लॉग आउट हैं या लॉग आउट हैं)। सीएसआरएफ टोकन प्रत्येक पृष्ठ लोड पर आपके पृष्ठ में शामिल है। लॉग आउट पर, आपका सत्र रीसेट हो गया है और इसमें कोई सीएसआरएफ टोकन नहीं है। आम तौर पर, एक लॉगआउट एक अलग पृष्ठ / क्रिया के लिए रीडायरेक्ट करता है, जो आपको एक नया सीएसआरएफ टोकन देता है, लेकिन जब से आप एजेक्स का प्रयोग कर रहे हैं, आपको मैन्युअल रूप से यह करना होगा।

  • आपको अपना नया सीएसआरएफ टोकन वापस करने के लिए डेविज़ सत्र नियंत्रक :: नष्ट पद्धति को ओवरराइड करना होगा।
  • फिर क्लाइंट साइड पर आपको अपने लॉगआउट XMLHttpRequest के लिए एक सफल हेन्डलर सेट करना होगा। उस हैंडलर में आपको प्रतिक्रिया से यह नया सीएसआरएफ टोकन लेना होगा और इसे अपने $('meta[name="csrf-token"]').attr('content', <NEW_CSRF_TOKEN>) में सेट करना होगा: $('meta[name="csrf-token"]').attr('content', <NEW_CSRF_TOKEN>)

अधिक विस्तृत स्पष्टीकरण आपके पास सबसे अधिक संभावना है कि आपकी ApplicationController.rb फ़ाइल में protect_from_forgery सेट हो गई है, जिससे आपके सभी अन्य नियंत्रक का उत्तराधिकार होता है (यह मुझे लगता है कि यह बहुत आम है)। protect_from_forgery सभी गैर- GET HTML / Javascript अनुरोधों पर protect_from_forgery चेक करता है। चूंकि डेविस लॉग इन एक पोस्ट है, इसलिए यह सीएसआरएफ चेक करता है। यदि कोई सीएसआरएफ जांच विफल हो जाता है तो उपयोगकर्ता का मौजूदा सत्र साफ़ हो जाता है, यानी, उपयोगकर्ता को लॉग आउट करता है, क्योंकि सर्वर मानता है कि यह एक हमला है (जो सही / वांछित व्यवहार है)।

तो मान लें कि आप लॉग आउट स्थिति में शुरू कर रहे हैं, आप एक ताज़ा पृष्ठ लोड करते हैं, और पृष्ठ को पुन: लोड नहीं करते हैं:

  1. पृष्ठ को प्रतिपादन करने पर: सर्वर आपके सर्वर सत्र से संबंधित पृष्ठ में सीएसआरएफ टोकन सम्मिलित करता है। आप अपने टोकन $('meta[name="csrf-token"]').attr('content') में एक जावास्क्रिप्ट कंसोल से निम्नलिखित को चलाकर इस टोकन को देख सकते हैं। $('meta[name="csrf-token"]').attr('content')

  2. आप फिर एक XMLHttpRequest के माध्यम से साइन इन करें: आपका सीएसआरएफ टोकन इस बिंदु पर अपरिवर्तित रहता है, इसलिए आपके सत्र में सीएसआरएफ टोकन अभी भी उस पृष्ठ से मेल खाता है जो पृष्ठ में डाला गया था। परिदृश्य के पीछे, ग्राहक पक्ष पर, jquery-ujs xhr के लिए सुन रहा है और $('meta[name="csrf-token"]').attr('content') के मूल्य के साथ 'एक्स-सीएसआरएफ-टोकन' हेडर सेट कर रहा है। $('meta[name="csrf-token"]').attr('content') लिए स्वचालित रूप से (याद रखें कि यह सीएसआरएफ टोकन सेट को चरण 1 में तोड़ दिया गया था)। सर्वर टोकन सेट को jquery-ujs और जो आपके सत्र की जानकारी में संग्रहीत है, उनके द्वारा शीर्षलेख में तुलना करता है और वे मेल खाते हैं, इसलिए अनुरोध सफल होता है।

  3. आप फिर एक XMLHttpRequest के माध्यम से लॉग आउट करें: यह रीसेट करता है, आपको सीएसआरएफ टोकन के बिना एक नया सत्र देता है।

  4. आप फिर एक XMLHttpRequest के माध्यम से साइन इन करें: jquery-ujs $('meta[name="csrf-token"]').attr('content') के मूल्य से सीएसआरएफ टोकन को खींचती है। $('meta[name="csrf-token"]').attr('content') । यह मान अभी भी आपके पुराने सीएसआरएफ टोकन है। यह इस पुराने टोकन को लेता है और 'एक्स-सीएसआरएफ-टोकन' सेट करने के लिए इसका इस्तेमाल करता है सर्वर इस हैडर मान की तुलना एक नए सीएसआरएफ टोकन के साथ करता है जो आपके सत्र में जोड़ता है, जो अलग है। यह अंतर protect_form_forgery को असफल होने का कारण बनता है, जो WARNING: Can't verify CSRF token authenticity फेंकता है WARNING: Can't verify CSRF token authenticity protect_form_forgery WARNING: Can't verify CSRF token authenticity और आपके सत्र को पुन: सेट WARNING: Can't verify CSRF token authenticity , जो उपयोगकर्ता को लॉग आउट करता है।

  5. फिर आप एक और XMLHttpRequest बना सकते हैं जिसके लिए लॉग इन उपयोगकर्ता की आवश्यकता होती है: वर्तमान सत्र में कोई लॉग इन उपयोगकर्ता नहीं है, इसलिए एक 401 रिटर्न देता है।

अपडेट करें: 8/14 डिव्इस लॉगआउट आपको एक नया सीएसआरएफ टोकन नहीं देता है, सामान्य रूप से एक लॉगआउट के बाद होने पर रीडायरेक्ट आपको एक नया सीएसआरएफ टोकन देता है।

मेरा जवाब जिम्बो और @ सिजा दोनों से भारी उधार लेता है, हालांकि मैं रेलवे सीएसआरएफ संरक्षण + Angular.js पर सुझाव / devotion / angularjs सम्मेलन का उपयोग कर रहा हूं : protect_from_forgery मुझे POST पर लॉग आउट करने देता है , और मेरे ब्लॉग पर थोड़ा विस्तारित करता है जब मैं मूल रूप से यह किया था Csrf के लिए कुकीज़ सेट करने के लिए इस अनुप्रयोग नियंत्रक पर एक विधि है:

 after_filter :set_csrf_cookie_for_ng def set_csrf_cookie_for_ng cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? end 

इसलिए मैं @ स्याजा के प्रारूप का उपयोग कर रहा हूं, लेकिन उस पहले के समाधान से कोड का उपयोग करके, मुझे दे रहा हूं:

 class SessionsController < Devise::SessionsController after_filter :set_csrf_headers, only: [:create, :destroy] protected def set_csrf_headers cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? end end 

पूर्णता के लिए, चूंकि मुझे इसे काम करने के लिए कुछ मिनट लग गए, मैं यह भी बताता हूं कि आप अपने कॉन्फिग / रुट्स। आरबी को संशोधित करने की आवश्यकता है कि आपने सत्र नियंत्रक को ओवरराइड कर दिया है। कुछ इस तरह:

 devise_for :users, :controllers => {sessions: 'sessions'} 

यह एक बड़ी सीएसआरएफ सफाई का भी हिस्सा था जिसे मैंने अपने आवेदन पर किया है, जो दूसरों के लिए दिलचस्प हो सकता है ब्लॉग पोस्ट यहाँ है , अन्य परिवर्तनों में शामिल हैं:

ActionController से बचाव :: InvalidAuthenticityToken, जिसका मतलब है कि अगर चीजें एक बार फिर से बाहर निकलती हैं, तो एप्लिकेशन को उपयोगकर्ता को ठीक करने के बजाय, कुकीज़ साफ़ करने की आवश्यकता होगी। जैसा कि चीजें रेल में खड़े हैं मुझे लगता है कि आपके एप्लिकेशन नियंत्रक को इस प्रकार से चूक दिया जाएगा:

 protect_from_forgery with: :exception 

उस स्थिति में, आपको तब चाहिए:

 rescue_from ActionController::InvalidAuthenticityToken do |exception| cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? render :error => 'invalid token', {:status => :unprocessable_entity} end 

मुझे दौड़ की परिस्थितियों के साथ कुछ दु: ख और डिवाइज़ में टाइमआउट करने योग्य मॉड्यूल के साथ कुछ इंटरैक्शन भी मिला है, जिस पर मैंने ब्लॉग पोस्ट में आगे टिप्पणी की है – संक्षेप में आपको cookie_store के बजाय active_record_store का उपयोग करने पर विचार करना चाहिए, और समानांतर जारी करने के बारे में सावधान रहना चाहिए sign_in और sign_out कार्यों के पास के अनुरोध

यह मेरा लेना है:

 class SessionsController < Devise::SessionsController after_filter :set_csrf_headers, only: [:create, :destroy] respond_to :json protected def set_csrf_headers if request.xhr? response.headers['X-CSRF-Param'] = request_forgery_protection_token response.headers['X-CSRF-Token'] = form_authenticity_token end end end 

और ग्राहक पक्ष पर:

 $(document).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); } }); 

जो आपके सीएसआरएफ मेटा टैग को हर बार जब आप X-CSRF-Token या X-CSRF-Param अनुरोध के जरिए X-CSRF-Param हेडर लौटाएंगे, तो उनका क्या होगा?

वार्डन स्रोत पर खुदाई करने के बाद, मैंने देखा कि false sign_out_all_scopes सेट करना पूरे सत्र को साफ करने से वार्डन को रोकता है, इसलिए सीएसआरएफ टोकन साइन-आउट के बीच संरक्षित है।

डिवीज़ इश्यू टैकर पर संबंधित चर्चा: https://github.com/plataformatec/devise/issues/2200

मैंने इसे अपने लेआउट फाइल में जोड़ा और यह काम किया

  <%= csrf_meta_tag %> <%= javascript_tag do %> jQuery(document).ajaxSend(function(e, xhr, options) { var token = jQuery("meta[name='csrf-token']").attr("content"); xhr.setRequestHeader("X-CSRF-Token", token); }); <% end %> 

जांचें कि आपने इसे अपने application.js फ़ाइल में शामिल किया है या नहीं

// जरूरी आवश्यकता jquery

// जरूरी jquery_ujs

कारण यह है कि jquery-rails मणि जो स्वचालित रूप से डिफ़ॉल्ट रूप से सभी अजाक्स अनुरोधों पर सीएसआरएफ टोकन सेट करता है, उन दोनों की आवश्यकता है

मेरे मामले में, उपयोगकर्ता को लॉगिन करने के बाद, मुझे उपयोगकर्ता के मेनू को फिर से करना होगा। यह काम किया, लेकिन मुझे सर्वर पर हर अनुरोध पर सीएसआरएफ प्रामाणिकता त्रुटियां मिलीं, उसी खंड में (पेज को ताज़ा करने के बिना)। ऊपर से समाधान काम नहीं कर रहा था क्योंकि मुझे जेएस दृश्य प्रस्तुत करने की आवश्यकता थी।

मैंने यह किया है, यंत्रवत् का उपयोग कर:

एप्लिकेशन / नियंत्रक / sessions_controller.rb

  class SessionsController < Devise::SessionsController respond_to :json # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? if request.format.json? markup = render_to_string :template => "devise/sessions/popup_login", :layout => false render :json => { :data => markup }.to_json else respond_with(resource, serialize_options(resource)) end end # POST /resource/sign_in def create if request.format.json? self.resource = warden.authenticate(auth_options) if resource.nil? return render json: {status: 'error', message: 'invalid username or password'} end sign_in(resource_name, resource) render json: {status: 'success', message: '¡User authenticated!'} else self.resource = warden.authenticate!(auth_options) set_flash_message(:notice, :signed_in) sign_in(resource_name, resource) yield resource if block_given? respond_with resource, location: after_sign_in_path_for(resource) end end end 

इसके बाद मैंने नियंत्रक # कार्रवाई करने का अनुरोध किया जो मेनू को फिर से तैयार करता है। और जावास्क्रिप्ट में, मैंने एक्स-सीएसआरएफ-परम और एक्स-सीएसआरएफ-टोकन को संशोधित किया है:

एप्लिकेशन / विचारों / उपयोगिताओं / redraw_user_menu.js.erb

  $('.js-user-menu').html(''); $('.js-user-menu').append('<%= escape_javascript(render partial: 'shared/user_name_and_icon') %>'); $('meta[name="csrf-param"]').attr('content', '<%= request_forgery_protection_token.to_s %>'); $('meta[name="csrf-token"]').attr('content', '<%= form_authenticity_token %>'); 

मुझे आशा है कि किसी एक के लिए यह एक ही जेएस स्थिति पर उपयोगी है 🙂

@ 604bit की एक टिप्पणी के उत्तर में; यदि आप इस त्रुटि में चलते हैं:

 Unexpected error while processing request: undefined method each for :authenticity_token:Symbol` 

बदलने के

 response.headers['X-CSRF-Param'] = request_forgery_protection_token 

साथ में

 response.headers['X-CSRF-Param'] = request_forgery_protection_token.to_s