20

我正在使用devise(最新版本 - 3.2.0)和rails(最新版本 - 4.0.1)

我正在进行简单的身份验证(没有 ajax 或 api)并收到 CSRF 真实性令牌错误。检查下面的 POST 请求

started POST "/users/sign_in" for 127.0.0.1 at 2013-11-08 19:48:49 +0530
Processing by Devise::SessionsController#create as HTML

 Parameters: {"utf8"=>"✓",    
 "authenticity_token"=>"SJnGhXXUXjncnPhCdg3muV2GYCA8CX2LVFV78pqddD4=", "user"=> 
{"email"=>"a@a.com", "password"=>"[FILTERED]", "remember_me"=>"0"},
"commit"=>"Sign in"}

Can't verify CSRF token authenticity
 User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."email" =  
'a@a.com' LIMIT 1
(0.1ms)  begin transaction
SQL (0.4ms)  UPDATE "users" SET "last_sign_in_at" = ?, "current_sign_in_at" = ?,
"sign_in_count" = ?, "updated_at" = ? WHERE "users"."id" = 2  [["last_sign_in_at", Fri,
08 Nov 2013 14:13:56 UTC +00:00], ["current_sign_in_at", Fri, 08 Nov 2013 14:18:49 UTC
+00:00], ["sign_in_count", 3], ["updated_at", Fri, 08 Nov 2013 14:18:49 UTC +00:00]]
(143.6ms)  commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 239ms (ActiveRecord: 144.5ms | Search: 0.0ms)

根 url 指向home#new,就像

class HomeController < ApplicationController
   before_action :authenticate_user!
   def index
   end
end

Sign_in 页面生成的 html 视图如下:

  • 元标记

    <meta content="authenticity_token" name="csrf-param" />
    <meta content="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" name="csrf-token" />
    
  • 形式

    <form accept-charset="UTF-8" action="/users/sign_in" class="new_user" id="new_user" 
    method="post">
    <div style="margin:0;padding:0;display:inline">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden
    value="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" />
    </div>
    <div><label for="user_email">Email</label><br />
    <input autofocus="autofocus" id="user_email" name="user[email]" type="email" value="" />
    </div>
    
    <div><label for="user_password">Password</label><br />
    <input id="user_password" name="user[password]" type="password" /></div>
    
    <div><input name="user[remember_me]" type="hidden" value="0" />
    <input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1" /> 
    <label for="user_remember_me">Remember me</label></div>
    
    <div><input name="commit" type="submit" value="Sign in" /></div>
    </form>
    

身份验证请求甚至会更新last_sign_in_atsign_in_count值,但是当我尝试current_user在控制器中访问时,它会以nil.

据我说,它实际上并没有登录user。但随之而来的问题是“为什么它在表中更新last_sign_in_at/sign_in_countuser?”

4

4 回答 4

14

当 CSRF 令牌不正确时,Rails 不会读取或更新会话。它仍然会执行控制器指定的任何其他操作,这解释了为什么您看到数据库更新但最终没有登录。

我注意到您的日志和页面中的authentity_token 不匹配。我意识到这可能是因为您捕获了不同的请求,但您应该检查页面上的请求是否与日志中的请求匹配。我还假设您在视图中使用了正确的标签,每次都会生成不同的authentity_token,而不仅仅是对HTML输入进行硬编码。

您是否看到与设计无关的表单存在同样的问题?如果没有,作为一种解决方法,您可以使用控制器中的以下代码使您的操作免于 CSRF 检查:

protect_from_forgery except: :sign_in

CSRF 攻击针对您的登录操作的可能性对我来说似乎非常遥远(<-pun)。

另外,如果只是设计,那么我建议您向他们提出问题,您已经完成了

于 2013-11-16T03:43:54.153 回答
6

在应用程序控制器上添加它(这适用于 Rails 5)

protect_from_forgery unless: -> { request.format.json? }

将此添加到设计 SessionController

skip_before_action :verify_authenticity_token, only: [:create]

用 curl 试试

curl -X POST -v -H 'Content-Type: application/json' http://0.0.0.0:3000/users/sign_in -d '{"user" : {"email": "name@mail.com", "password": "secret" }}'
于 2018-08-28T21:29:06.253 回答
2

设计 gem 没有问题。我删除了“rails-api”gem,我的应用程序开始工作。

于 2013-12-06T04:06:59.943 回答
0

我修复了同样的问题,只是在视图中删除了“remote: true”选项:将 form_for(model, remote: true) 更改为 form_for(model)

于 2017-09-18T09:54:46.530 回答