Ruby-on-rails 在 Rails 中创建唯一令牌的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6021372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to create unique token in Rails?
提问by Slick23
Here's what I'm using. The token doesn't necessarily have to be heard to guess, it's more like a short url identifier than anything else, and I want to keep it short. I've followed some examples I've found online and in the event of a collision, I thinkthe code below will recreate the token, but I'm not real sure. I'm curious to see better suggestions, though, as this feels a little rough around the edges.
这是我正在使用的。不一定非要听到令牌才能猜测,它更像是一个简短的 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
My database column for the token is a unique index and I'm also using validates_uniqueness_of :tokenon the model, but because these are created in batches automatically based on a user's actions in the app (they place an order and buy the tokens, essentially), it's not feasible to have the app throw an error.
我的令牌数据库列是一个唯一索引,我也在validates_uniqueness_of :token模型上使用,但是因为这些是根据用户在应用程序中的操作(他们下订单并购买令牌,本质上)自动批量创建的,它是让应用程序抛出错误是不可行的。
I could also, I guess, to reduce the chance of collisions, append another string at the end, something generated based on the time or something like that, but I don't want the token to get too long.
我想,为了减少冲突的机会,我也可以在末尾附加另一个字符串,根据时间生成的东西或类似的东西,但我不希望令牌变得太长。
回答by Krule
-- Update --
- 更新 -
As of January 9th, 2015.the solution is now implemented in Rails 5ActiveRecord's secure token implementation.
截至2015 年 1 月 9 日,该解决方案现已在Rails 5 ActiveRecord 的安全令牌实现中实现。
-- Rails 4 & 3 --
-- 导轨 4 和 3 --
Just for future reference, creating safe random token and ensuring it's uniqueness for the model (when using Ruby 1.9 and ActiveRecord):
仅供将来参考,创建安全的随机令牌并确保模型的唯一性(使用 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
Edit:
编辑:
@kainsuggested, and I agreed, to replace begin...end..whilewith loop do...break unless...endin this answer because previous implementation might get removed in the future.
@kain建议,我同意,在此答案中替换begin...end..while为loop do...break unless...end,因为将来可能会删除以前的实现。
Edit 2:
编辑2:
With Rails 4 and concerns, I would recommend moving this to concern.
对于 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
回答by Nate Bird
Ryan Bates uses a nice little bit of code in his Railscast on beta invitations. This produces a 40 character alphanumeric string.
Ryan Bates 在他的Railscast 测试邀请中使用了一些不错的代码。这将生成一个 40 个字符的字母数字字符串。
Digest::SHA1.hexdigest([Time.now, rand].join)
回答by Marius Pop
This might be a late response but in order to avoid using a loop you can also call the method recursively. It looks and feels slightly cleaner to me.
这可能是一个迟到的响应,但为了避免使用循环,您也可以递归调用该方法。对我来说,它看起来和感觉都更干净了。
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
回答by coreyward
There are some pretty slick ways of doing this demonstrated in this article:
本文演示了一些非常巧妙的方法来做到这一点:
My favorite listed is this:
我最喜欢的列表是这样的:
rand(36**8).to_s(36)
=> "uur0cj2h"
回答by Esse
If you want something that will be unique you can use something like this:
如果你想要一些独一无二的东西,你可以使用这样的东西:
string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")
however this will generate string of 32 characters.
但是这将生成 32 个字符的字符串。
There is however other way:
然而还有其他方式:
require 'base64'
def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end
for example for id like 10000, generated token would be like "MTAwMDA=" (and you can easily decode it for id, just make
例如,对于像 10000 这样的 id,生成的令牌将类似于“MTAwMDA=”(您可以轻松地将其解码为 id,只需制作
Base64::decode64(string)
回答by Vik
This may be helpful :
这可能会有所帮助:
SecureRandom.base64(15).tr('+/=', '0aZ')
If you want to remove any special character than put in first argument '+/=' and any character put in second argument '0aZ' and 15 is the length here .
如果你想删除任何特殊字符而不是放在第一个参数 '+/=' 中,并且任何字符放在第二个参数 '0aZ' 和 15 是这里的长度。
And if you want to remove the extra spaces and new line character than add the things like :
如果您想删除多余的空格和换行符,请添加以下内容:
SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")
Hope this will help to anybody.
希望这对任何人都有帮助。
回答by Nickolay Kondratenko
Try this way:
试试这个方法:
As of Ruby 1.9, uuid generation is built-in. Use the SecureRandom.uuidfunction.
Generating Guids in Ruby
从 Ruby 1.9 开始,内置了 uuid 生成。使用该SecureRandom.uuid功能。
在 Ruby 中生成指南
This was helpful for me
这对我很有帮助
回答by user2627938
you can user has_secure_token https://github.com/robertomiranda/has_secure_token
您可以使用 has_secure_token https://github.com/robertomiranda/has_secure_token
is really simple to use
使用起来非常简单
class User
has_secure_token :token1, :token2
end
user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"
回答by Aaron Henderson
To create a proper, mysql, varchar 32 GUID
创建正确的 mysql varchar 32 GUID
SecureRandom.uuid.gsub('-','').upcase
回答by miosser
def generate_token
self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--")
end

