Erreur "ActionController :: InvalidAuthenticityToken" lors de l'utilisation de form_with

Sep 16 2020

J'ai un formulaire qui ressemble à ceci:

  <%= 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 %> 

Immédiatement après la soumission du formulaire:

Remarques:

  • Cela se produit dans une application (pas une API), les sessions sont donc importantes, par conséquent la protection CSRF doit être laissée activée.
  • Le problème se produit dans Chrome, Incognito et Safari.
  • J'ai essayé de me connecter avec différents utilisateurs et de supprimer les cookies (au cas où cela serait causé par un jeton périmé )

Un peu plus du message d'erreur:

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'

Mettre à jour

Je suis revenu à la dernière version de travail du formulaire, qui était exactement la même que ci-dessus mais sans , local: true. Puis ça marche soudainement! (aucune erreur).

J'ai pensé local: true(ou remote: false) désactiver simplement la soumission de formulaire ajax. Donc je ne comprends pas pourquoi cela ferait une différence (ou aurait quelque chose à voir avec CSRF), il semble que ces deux aspects ne soient pas liés et il n'est pas clair pourquoi ces deux concepts auraient un effet l'un sur l'autre

Mise à jour 2

Je me suis rendu compte plus tard qu'une autre forme de travail auparavant intacte produisait également cette erreur. Cela n'avait en aucun cas été changé. Je l'ai essayé dans Chrome Incognito, et cela a produit l'erreur. Une demi-heure plus tard (sans changer de code), je l'ai réessayé dans le même navigateur et cela a fonctionné. Ce comportement (très) étrange me fait penser que c'est quelque chose à voir avec les sessions, les cookies ou la mise en cache. Je ferai un rapport si j'apprends quelque chose de plus

Mise à jour 3

Après avoir lu la solution de Sarah en ajoutant protect_from_forgery prepend: trueau contrôleur d'application (j'ai essayé à la fois avant et après before_action :authenticate_user!), le même message d'erreur apparaît dans les journaux, la demande POST n'est pas traitée, mais l'application redirige vers la page d'accueil. Ie sur POST je vois:

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)

Mise à jour 4

J'ai essayé de vider manuellement le cache de fragments de rails (avec Rails.cache.clear ). Mais le résultat est exactement le même avant / après la suppression du cache de fragments.

Réponses

2 SarahMarie Sep 17 2020 at 06:46

Je me souviens avoir rencontré quelque chose comme ça et avoir ajouté protect_from_forgery prepend: trueavant toute authentification utilisateur à la ApplicationControllersolution.

1 stevec Sep 17 2020 at 20:18

TL; DR: après 2 semaines de tentatives de débogage, j'ai désactivé les turbolinks et le problème a disparu .

En plus de désactiver les turbolinks, une autre solution semble être (mentionnée ici ) en ajoutant ceci àapplication.js

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

Réponse précédente

Le problème revenait sans cesse. J'ai essayé les six choses suivantes mais cela ne l'a toujours pas résolu

1. Effacez le cache de fragments

Rails.cache.clear( avertissement car il efface le cache, il supprimera également des choses comme les tâches sidekiq, etc.). Cela supprimera le jeton périmé et l'actualisation de l'application dans le navigateur reviendra à la normale, et le formulaire devrait être soumis (un simple `` resoumettre '' ne fonctionnera pas, alors revenez à la page du formulaire, actualisez, puis soumettez-le et il devrait travail)

2. Page d'actualisation matérielle

Appuyez sur cmd+ opt+ jpour afficher la console développeur, puis cliquez avec le bouton droit sur actualiser et sélectionnez `` Vider le cache et recharger dur ''

3. Supprimer les cookies du site

Faites un clic droit sur la petite icône à gauche immédiate de l'url (ce sera un verrou si vous utilisez https, ou la lettre «i» si vous utilisez http). Entrez dans chacune des catégories répertoriées (par exemple, «Cookies», «Paramètres du site», etc.) et supprimez-les toutes

4. Supprimez les cookies pour les autres URL qui pointent vers le même site

Par exemple, si votre site est www.example.comhébergé sur heroku à www.example.herokuapp.com, supprimez également les cookies de cette deuxième URL.

5. Supprimer les cookies pour localhost

J'ai supprimé les cookies localhost juste pour être sûr

6. Test dans des instances de chrome complètement isolées