0

我们的产品是一个 Rails 应用程序;身份验证由 Devise 和 OmniAuth 处理。总共约 2000 个用户。我们最近收到了一些用户无法登录的报告,但我们无法弄清楚原因。在我们的生产日志中没有收到任何服务器错误或任何内容来暗示任何事情都是错误的。

让我们看一些代码……</p>

class OmniauthCallbacksController < Devise::OmniauthCallbacksController

  ...

  def twitter
    oauthorize "twitter"
  end

  private

  def oauthorize(provider)
    if env['omniauth.auth']
      @identity = Identity.from_omniauth(env['omniauth.auth'])
      @person = @identity.person
      # 1. failing here? Maybe?
      if @person
        PersonMeta.create_for_person(@person, session[:referrer], session[:landing_page]) if @person.first_visit?
        # 2. PersonMetas *aren't* being created.
        flash[:notice] = I18n.t("devise.omniauth_callbacks.success", kind: provider)
        sign_in_and_redirect(@person, :event => :authentication)
        # 3. Definitely failing by here…
      else
        redirect_to root_url
      end
    else
      redirect_to root_url
    end
  end
end

class Identity < ActiveRecord::Base
  belongs_to :person, counter_cache: true, touch: true
  after_create :check_person

  def self.from_omniauth(auth)
    where(auth.slice("provider", "uid")).first_or_initialize.tap do |identity|
      identity.oauth_token = auth['credentials']['token']
      identity.oauth_secret = auth['credentials']['secret']
      case auth['provider']
      when "twitter"
        identity.name = auth['info']['name']
        identity.nickname = auth['info']['nickname']
        identity.bio = auth['info']['description']
        identity.avatar_address = auth['info']['image']
      else
        raise "Provider #{provider} not handled"
      end
      identity.save
    end
  end

  def check_person
    if person_id.nil?
      p = create_person(nickname: nickname, name: name, remote_avatar_url: biggest_avatar)
      p.identities << self
    end
  end

  def biggest_avatar
    avatar_address.gsub('_bigger', '').gsub('_normal', '') if avatar_address
  end
end

class PersonMeta < ActiveRecord::Base
  attr_accessible :landing_page, :mixpanel_id, :referrer_url, :person_id
  belongs_to :person

  def self.create_for_person(person, referrer, landing_page)
    PersonMeta.create!(referrer_url: referrer, landing_page: landing_page, person_id: person.id)
  end
end

所以我们有了它,而且我们在生产中没有遇到任何错误。

我们从哪里开始?好吧,让我们看看失败点是不是Identity.from_omniauth

此方法搜索现有身份(我们为更多提供者编写了额外的代码,但尚未在客户端实现)。如果没有找到身份,它将创建一个,然后创建关联的 Person 模型。如果这是故障点,我们将能够在生产控制台中看到一些可疑的空字段。但是没有——Person & Identity 模型已经创建了所有正确的字段,并且应用程序的相关部分已经看到了它们(例如,它们的“用户个人资料页面”都已创建)。

我刚刚添加if @person到#oauthorize - 我们有一个 500 where @identity.personwas nil,但无法复制。

无论如何,有问题的现实世界用户确实拥有完整的模型和完整的关联。向下移动方法,然后我们创建一个PersonMeta记录来记录简单的东西,比如登陆页面。我会这样做after_createPerson但我认为将会话数据传递给模型是不正确的。

这不是为我们有问题的用户创建的。在这一点上,我有点难过。我不确定如何创建(砰的一声)进去了,但是如果东西坏了,这不应该抛出异常吗?它不是。

无论如何,只有当这是一个人的第一次访问时才会调用它 - 后续登录应该绕过它。有问题的用户之一是我的朋友,所以我一直在让他尝试各种其他事情,包括再次登录、尝试不同的浏览器等,而且这种情况一直在发生

所以无论如何,在花了 45 分钟写这篇文章之后……</h1>

其中一名用户通过 Twitter 撤销了对该应用程序的访问权限并重新进行了身份验证。现在一切正常。

我勒个去?

他的旧身份正确存储他的 OAuth 令牌等。

幸运的是,这已为一位用户解决,但这显然是一个持续存在的问题。

我们做什么?

4

1 回答 1

0

identity.save线路输入是否有可能Identity.from_omniauth静默失败?如果是这样,你的after_create钩子将不会运行,@identity.person将是nil,你只会(默默地)重定向。

试试identity.save!

于 2013-07-01T09:07:48.683 回答