为了账号安全,请及时绑定邮箱和手机立即绑定

在Rails中创建唯一令牌的最佳方法?

/ 猿问

在Rails中创建唯一令牌的最佳方法?

翻阅古今 2020-02-03 15:05:16

这就是我正在使用的。令牌不必一定要猜测,它更像是一个简短的url标识符,而不是其他任何东西,我想使其简短。我遵循了一些我在网上找到的示例,如果发生碰撞,我认为下面的代码将重新创建令牌,但是我不确定。不过,我很好奇看到更好的建议,因为这样的感觉有些粗糙。


def self.create_token

    random_number = SecureRandom.hex(3)

    "1X#{random_number}"


    while Tracker.find_by_token("1X#{random_number}") != nil

      random_number = SecureRandom.hex(3)

      "1X#{random_number}"

    end

    "1X#{random_number}"

  end

我的令牌数据库列是唯一索引,我也在validates_uniqueness_of :token模型上使用它,但是因为这些是根据用户在应用程序中的操作自动创建的(它们实际上是下订单并购买令牌)而批量创建,所以让应用抛出错误是不可行的。


我想,我也可以减少冲突的机会,在末尾附加另一个字符串,这些字符串是基于时间生成的,或者类似的东西,但是我不希望令牌太长。


查看完整描述

3 回答

?
一只萌萌小番薯

自2015年1月9日起,该解决方案现已在Rails 5 ActiveRecord的安全令牌实现中实现。


-Rails 4和3-


仅供以后参考,创建安全的随机令牌并确保它对于模型是唯一的(使用Ruby 1.9和ActiveRecord时):


class ModelName < ActiveRecord::Base


  before_create :generate_token


  protected


  def generate_token

    self.token = loop do

      random_token = SecureRandom.urlsafe_base64(nil, false)

      break random_token unless ModelName.exists?(token: random_token)

    end

  end


end

编辑:


@kain建议(并且我同意)begin...end..while用loop do...break unless...end此答案替换,因为以前的实现可能会在将来被删除。


编辑2:


对于Rails 4和关注点,我建议将其转移到关注点上。


# app/models/model_name.rb

class ModelName < ActiveRecord::Base

  include Tokenable

end


# app/models/concerns/tokenable.rb

module Tokenable

  extend ActiveSupport::Concern


  included do

    before_create :generate_token

  end


  protected


  def generate_token

    self.token = loop do

      random_token = SecureRandom.urlsafe_base64(nil, false)

      break random_token unless self.class.exists?(token: random_token)

    end

  end

end


查看完整回答
反对 回复 2020-02-03
?
扬帆大鱼

瑞安·贝茨(Ryan Bates)在Railscast中针对Beta版邀请使用了一些代码。这将产生一个40个字符的字母数字字符串。


Digest::SHA1.hexdigest([Time.now, rand].join)


查看完整回答
反对 回复 2020-02-03
?
白衣染霜花

这可能是一个较晚的响应,但是为了避免使用循环,您还可以递归调用该方法。它看起来和感觉对我来说都比较干净。


class ModelName < ActiveRecord::Base


  before_create :generate_token


  protected


  def generate_token

    self.token = SecureRandom.urlsafe_base64

    generate_token if ModelName.exists?(token: self.token)

  end


end


查看完整回答
反对 回复 2020-02-03

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信