第一次发送设定确认无效 [英] Devise Confirmation invalid on first send

查看:189
本文介绍了第一次发送设定确认无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Rise 4应用程序与Devise 3.2.2使用:可确认,并遇到一个问题,它发送无效的确认令牌,但只有第一次。重新发送确认令牌后,链接可以正常工作。

I have a Rails 4 app with Devise 3.2.2 using :confirmable, and am running into an issue with it sending invalid confirmation tokens, but only the first time. After you resend the confirmation token, the link works.

相关路线:

devise_for :users, skip: [:sessions, :passwords, :confirmations, :unlocks, :registrations, :invitations]
as :user do
  ...
  # joining
  get   '/register' => 'devise/registrations#new',    as: 'new_user_registration'
  post  '/register' => 'devise/registrations#create', as: 'user_registration'
  ...
end

...和相关邮件模板:

...and the mail template in question:

<p>Welcome <%= @email %>!</p>

<p>You can confirm your account email through the link below:</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>

据我所知,一切都是非常标准的票价,事实上只有当

As far as I can tell, everything is pretty standard fare, and the fact that it only fails when initially creating and not on the resend is rather confusing.

- 更新 -

当点击链接时,我在开发日志中得到以下内容:

When clicking on the link, I get the following in my dev log:

Started GET "/account/confirm?confirmation_token=3bQP-EvYJPv74s9AMz63" for 127.0.0.1 at 2014-02-07 12:26:10 -0500
Processing by Users::ConfirmationsController#show as HTML
  Parameters: {"confirmation_token"=>"3bQP-EvYJPv74s9AMz63"}
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'e191b48746f15014beb32073f08de3c7aa13a2282216f089fa71d083901b3dca' ORDER BY "users"."id" ASC LIMIT 1
  Rendered devise/shared/_links.slim (1.2ms)
  Rendered devise/confirmations/new.html.slim within layouts/devise (7.0ms)
  Rendered layouts/_jquery.slim (1.0ms)
Completed 200 OK in 32ms (Views: 23.4ms | ActiveRecord: 0.4ms)

引用的控制器是:

class Users::ConfirmationsController < Devise::ConfirmationsController

  protected

  def after_confirmation_path_for(resource_name, resource)
    if signed_in?
      signed_in_root_path(resource)
    else
      new_session_path(resource_name, email: resource.email)
    end
  end

end

- 更新2 -

以下是整个注册过程中日志的要点:$ b​​ $ b https:// gist.github.com/jbender/bbe079c2dd3fa2d1e664

The following is a gist of the logs from the entire signup process: https://gist.github.com/jbender/bbe079c2dd3fa2d1e664

推荐答案

看起来有一些事情导致你的用户在注册创建操作完成之前立即更新并重新保存(包括生成新的确认令牌)。看看你的要点:

It looks like there's something which is causing your user to be immediately updated and resaved (including generation of a new confirmation token) before the registration create action has finished. Looking at your gist:


  • 第5行显示使用电子邮件地址

  • 的现有用户的设计检查第6行显示设计检查其生成的确认令牌是否已存在于其他用户(显然它们需要唯一)

  • 第9行显示插入到数据库中的新用户记录

  • 然后,第11行看起来像是刚刚生成了一个新的确认令牌,正在检查这个新的令牌是否已经被使用。

  • 第14行显示已保存的更新的用户详细信息,包括此新的确认令牌。我注意到在第9行中的初始插入中没有一个tos_accepted_at字段。unconfirmed_email字段也已设置,并且confirm_sent_at字段比第9行中保存的字段晚1秒;这可能只是因为正常的:确定的行为,虽然我很惊讶的设计没有抓住这个事实,即电子邮件地址与现有的(未确认的)一样,而不是麻烦。

  • Line 5 shows devise checking for existing users with the email address
  • Line 6 shows devise checking whether the confirmation token it has just generated already exists for some other user (obviously they need to be unique)
  • Line 9 shows the new user record being inserted into your database
  • Line 11 then looks like devise has just generated a new confirmation token and is checking whether this new token is in use already.
  • Line 14 then shows updated user details being saved, including this new confirmation token. I notice that there is a tos_accepted_at field which wasn't present in the initial insert in line 9. The unconfirmed_email field has also been set and the confirmation_sent_at field is 1 second later than the one saved in line 9; this is probably just due to the normal :confirmable behaviour, though I'm surprised devise didn't catch the fact that the email address was the same as the existing (unconfirmed) one and not bother.

问题是为什么用户被保存了两次?看起来你已经添加了一个tos_accepted_at属性。是否有某些代码(后过滤器?)重新保存包含此属性的用户,以及所有其他代码,然后再次触发设备的可确认逻辑?说到这一点,我很感兴趣的是,由于confirm_sent_at时间戳更改,它没有立即导致发送第二封电子邮件(使用确认令牌)。

The question is why did the user get saved twice? It looks like you've added a tos_accepted_at attribute. Is there some code somewhere (an after filter?) resaving the user including this attribute, along with all the others, which then triggers devise's confirmable logic again? Speaking of which, I'm most intrigued that it didn't immediately cause a second email to be sent (with a confirmation token that works), given that the confirmation_sent_at timestamp changes.

我注意到还有一些版本跟踪,由其他INSERT判断,虽然看起来不像这样干扰。

I notice that there's some version tracking going on too, judging by other INSERTs, though it doesn't look like that can be interfering.

作为一个额外的理智检查一下,如果您可以对导轨控制台进行加密以加密您期望的确认令牌,则会发现加密版本与您的要点第6行的版本匹配,然后在第9行的数据库中覆盖该版本。不能尝试这个,因为它取决于你的rails的秘密(参见Devise :: TokenGenerator in devise / toekn_generator.rb)。无论如何,没有必要,但会确认原始确认令牌永远无法正常工作。

As an additional sanity check, if you could bludgeon the rails console into encrypting what you expect the confirmation token to be, you'd find that the encrypted version matches the version at line 6 of your gist, which is then overwritten in the db at line 9. I can't try this, because it depends on your rails secret (see Devise::TokenGenerator in devise/toekn_generator.rb). Anyway, not necessary, but would confirm that the original confirmation token is never going to work.

我认为重新发送工作是因为它只是正常情况(没有双重保存,没有额外的tos_accepted_at字段等)

I assume the resend works because it's just the normal case (no double save, no extra tos_accepted_at field etc.)

更新

正如评论中所讨论的,问题确实是tos_accepted_at属性。它正在使用 update_attribute() after_create 回调中进行更新。由于原因有些不清楚,这似乎使所有属性变脏,所以它们都被保存( update_attribute 也可以保存所有其他属性,如果它们是脏的)和设计产生了一个新的确认令牌,作为这个过程的一部分(尽管我们认为它不应该具有,因为电子邮件地址实际上没有改变!)。更改过滤器,保存更新的 tos_accepted_at before_save 过滤器而不是 after_create 通过确保用户只保存一次,因为 before_save 显然是在第一次保存之前发生的,而不是 after_create 当然这是在将用户插入数据库后的保存之后发生的。

As discussed in the comments, the problem was indeed the tos_accepted_at attribute. It was being updated using update_attribute() in an after_create callback. For reasons which are a bit unclear, this seemed to be dirtying all attributes, so they were all saved as well (update_attribute also saves all other attributes if they're dirty) and devise generated a new confirmation token as part of this process (though we don't think it should have as the email address hadn't actually changed!). Changing your filter which saved the updated tos_accepted_at to a before_save filter instead of after_create avoided the problem by making sure the user was only saved once, because before_save obviously happens before that first save as opposed to after_create which of course happens after the save which inserts the user into the db.

这篇关于第一次发送设定确认无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆