1

Michael Hartl のRuby on Rails Tutorialのような基本的な認証システムがあります。基本的に、記憶トークンは Cookie に保存されます。Railscast #124の Ryan Bate のBeta-Invitationsを実装しました。ここでは、限られた数の招待状を送信できます。そうこうしているうちに、現在のユーザーが招待を送った後にログアウトしてしまうという問題に遭遇しました。これは、招待モデルの次のコードが原因でした。

招待.rb

belongs_to :sender, :class_name => 'User'
[...]
before_create :decrement_sender_count, :if => :sender
[...]
def decrement_sender_count
  sender.decrement! :invitation_limit
end

ログで、sender.decrement! を見ました。Invitation_limit だけでなく、remember_token も更新しました。

UPDATE "users" SET "invitation_limit" = 9982, "remember_token" = 'PYEWo_om0iaMjwltU4iRBg', "updated_at" = '2012-07-06 09:57:43.354922' WHERE "users"."id" = 1

醜い回避策を見つけましたが、実際に何が問題なのか知りたいです。どこから始めたらいいのかわからないので、users コントローラーからの更新方法を紹介します。他に何が関連する可能性がありますか?

users_controller.rb

def update
  @user = User.find(params[:id])
  if @user.update_attributes(params[:user])
    flash[:success] = t('success.profile_save')
    sign_in @user
    redirect_to @user
  else
    flash.now[:error] = t('error.profile_save')
    render 'edit'
  end
end
4

2 に答える 2

2

私の意見では、ActiveRecordの更新方法によくある落とし穴があります。

ここでActiveRecordのドキュメントを見ると、デクリメントの実際の実装を確認できます。方法:

def decrement!(attribute, by = 1)
  decrement(attribute, by).update_attribute(attribute, self[attribute])
end

興味深い部分は、selfオブジェクトに対して呼び出されるupdate_attributeです。このメソッドは、ActiveRecordが指定された属性のみを更新することを意味しますが、実際には、selfオブジェクトのすべてのダーティ属性を更新します。

つまり、いずれかの時点で、オブジェクトの記憶トークン属性を変更すると、update_attributes呼び出し中にDBに保存されます。

私が正しく、それが問題である場合は、実行時にremember_token属性に変更が加えられていないことを確認してください。

それ以外に、オブジェクトに対してsaveメソッドを実行せずにDB上の単一の列を更新するActiveRecordのupdate_columnメソッドの使用を検討することができます

于 2012-07-06T10:21:05.223 に答える
2

decrement!saveもちろん、コールバックを保存して起動する呼び出し。その本があなたにそうするように指示しているようです

before_save :create_remember_token
def create_remember_token
  self.remember_token = SecureRandom.urlsafe_base64
end

つまり、ユーザーを保存すると、記憶トークンは常に無効になります。これは、ユーザーがパスワードを変更すると、記憶トークンも変更されるためだと思いますが、これは明らかに巻き添え被害があることを意味します。

あなたはdecrement_counter本質的にするものを使うことができます

update users set counter_name = counter_name - 1 where id =12345

コールバックを実行せずに。これにより、一部の競合状態のシナリオも回避されます。ただし、ユーザーが変更するたびにトークンを変更すると、予期しないときにトークンが変更されることになります。関連する場合(おそらくクレデンシャルが変更された場合)にのみトークンを変更することをお勧めします。

于 2012-07-06T10:30:00.833 に答える