Błąd „ActionController :: InvalidAuthenticityToken” podczas używania form_with

Sep 16 2020

Mam formularz, który wygląda tak:

  <%= form_with(url: star.starname, method: :post, local: true) do |f| %> 
    <% star.availabilities.each do |avail| %> 

    <%= f.label avail.time_slot %> 
      <%= radio_button_tag(:time_slot, avail.time_slot) %> <br>
    <% end %> 

  <%= f.submit "Create" %>
  <% end %> 

Natychmiast po przesłaniu formularza:

Uwagi:

  • Dzieje się tak w aplikacji (nie w API), więc sesje są ważne, dlatego ochrona CSRF musi być włączona.
  • Problem występuje w Chrome, incognito i safari.
  • Próbowałem zalogować się z różnymi użytkownikami i wyczyścić pliki cookie (na wypadek, gdyby było to spowodowane nieaktualnym tokenem )

Więcej informacji o błędzie:

Started POST "/talljohn" for ::1 at 2020-09-16 10:06:21 +1000
Processing by StarsController#book as HTML
  Parameters: {"authenticity_token"=>"P++4a+giwUBqZgCLfMwqKpMu0EGitd8zTOi5RWsnxpKlNcjiuU6hd3ebbIC/IOxlL74RJIvrq+yDuA1ZtfcvFw==", "time_slot"=>"2020-09-16 01:00:00 UTC", "commit"=>"Create", "starname"=>"talljohn"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 655)


  
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
  
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:215:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:247:in `handle_unverified_request'
devise (4.7.2) lib/devise/controllers/helpers.rb:255:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:242:in `verify_authenticity_token'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:428:in `block in make_lambda'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:200:in `block (2 levels) in halting'
actionpack (6.0.3.2) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:201:in `block in halting'

Aktualizacja

Powróciłem do ostatniej działającej wersji formularza, która była dokładnie taka sama jak powyżej, ale bez , local: true. Wtedy nagle działa! (bez błędów).

Pomyślałem local: true(lub remote: false) po prostu wyłącza przesyłanie formularza Ajax. Więc nie rozumiem, dlaczego miałoby to coś zmienić (lub ma cokolwiek wspólnego z CSRF), wydaje się, że te dwa aspekty są niezwiązane i nie jest jasne, dlaczego te dwie koncepcje miałyby na siebie jakikolwiek wpływ

Zaktualizuj 2

Później zdałem sobie sprawę, że inny nietknięty poprzednio działający formularz również spowodował ten błąd. Nie został w żaden sposób zmieniony. Wypróbowałem to w chrome incognito i spowodowało to błąd. Pół godziny później (bez zmiany kodu) spróbowałem ponownie w tej samej przeglądarce i zadziałało. To (bardzo) dziwne zachowanie sprawia, że ​​myślę, że ma to coś wspólnego z sesjami, plikami cookie lub pamięcią podręczną. Oddam raport, jeśli dowiem się czegoś więcej

Zaktualizuj 3

Po przeczytaniu dodania rozwiązania Sarahprotect_from_forgery prepend: true do kontrolera aplikacji (próbowałem zarówno przed, jak i po before_action :authenticate_user!), ten sam komunikat o błędzie pojawia się w dziennikach, żądanie POST nie jest wykonywane, ale aplikacja przekierowuje na stronę główną. To znaczy po POST widzę:

Can't verify CSRF token authenticity.
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 444)


Started GET "/users/sign_in" for ::1 at 2020-09-17 21:08:42 +1000
Processing by Devise::SessionsController#new as HTML
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Redirected to http://localhost:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.5ms | Allocations: 1900)

Zaktualizuj 4

Próbowałem ręcznie wyczyścić pamięć podręczną fragmentów szyn (za pomocą Rails.cache.clear ). Ale wynik jest dokładnie taki sam przed / po wyczyszczeniu pamięci podręcznej fragmentów.

Odpowiedzi

2 SarahMarie Sep 17 2020 at 06:46

Pamiętam, że wpadłem na coś takiego i dodałem protect_from_forgery prepend: trueprzed jakimkolwiek uwierzytelnieniem użytkownika do ApplicationControllerrozwiązania tego problemu.

1 stevec Sep 17 2020 at 20:18

TL; DR: po 2 tygodniach prób debugowania wyłączyłem turboliny i problem zniknął .

Oprócz wyłączenia turbolinków, wydaje się, że innym rozwiązaniem jest ( tutaj ) dodanie tegoapplication.js

$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });

Poprzednia odpowiedź

Problem powracał. Wypróbowałem następujące sześć rzeczy, ale nadal tego nie naprawiłem

1. Wyczyść pamięć podręczną fragmentów

Rails.cache.clear( ostrzeżenie, ponieważ czyści pamięć podręczną, usunie również takie rzeczy, jak zadania sidekiq itp.). Spowoduje to usunięcie nieaktualnego tokena, a odświeżenie aplikacji w przeglądarce przywróci normalne działanie, a formularz powinien zostać przesłany (proste „ponowne przesłanie” nie zadziała, więc wróć do strony formularza, odśwież, a następnie prześlij i powinno praca)

2. Twarde odświeżanie strony

Naciśnij cmd+ opt+, jaby wywołać konsolę programisty, a następnie kliknij prawym przyciskiem myszy na odświeżenie i wybierz `` Opróżnij pamięć podręczną i mocno załaduj ponownie ''

3. Usuń pliki cookie witryny

Kliknij prawym przyciskiem myszy małą ikonę po lewej stronie adresu URL (będzie to blokada, jeśli używasz https lub litera „i”, jeśli używasz http). Przejdź do każdej z wymienionych kategorii (np. „Pliki cookie”, „Ustawienia witryny” itp.) I usuń je wszystkie

4. Usuń pliki cookie z innych adresów URL, które kierują do tej samej witryny

Na przykład, jeśli Twoja witryna to www.example.comi jest hostowana na heroku pod adresem www.example.herokuapp.com, usuń pliki cookie również z tego drugiego adresu URL

5. Usuń pliki cookie dla localhost

Dla pewności usunąłem pliki cookie localhost

6. Testowanie w całkowicie izolowanych przypadkach chromu