Najlepszy sposób na stworzenie unikalnego tokena w Rails?
Oto, czego używam. Token niekoniecznie musi być słyszalny, aby się domyślić, jest to bardziej krótki identyfikator url niż cokolwiek innego i chcę go krótko trzymać. Skorzystałem z kilku przykładów, które znalazłem w Internecie i w razie kolizji, myślę, że poniższy kod odtworzy token, ale nie jestem pewien. Jestem jednak ciekaw lepszych sugestii, ponieważ wydaje się to trochę szorstkie na krawędziach.
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
Moja kolumna bazy danych dla tokena jest unikalnym indeksem i używam również validates_uniqueness_of :token
na modelu, ale ponieważ są one tworzone w partiach automatycznie na podstawie działań użytkownika w aplikacji (składają zamówienie i kupują tokeny, zasadniczo), nie jest możliwe, aby aplikacja wyrzuciła błąd.
Mógłbym też, jak sądzę, zmniejszyć ryzyko kolizji, dodać kolejny ciąg na końcu, coś generowanego na podstawie czasu lub coś w tym stylu, ale nie chcę, aby token był zbyt długi.
10 answers
-- Update --
Stan na 9 stycznia 2015. Rozwiązanie jest teraz zaimplementowane w Rails 5 ActiveRecord ' s secure token implementation .-- szyny 4 & 3 --
Tylko dla przyszłego odniesienia, tworzenie bezpiecznego tokenu losowego i zapewnienie jego unikalności dla modelu (przy użyciu Ruby 1.9 i 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:
@kain zasugerował, a ja zgodziłem się zastąpić begin...end..while
loop do...break unless...end
w tym odpowiedź, ponieważ poprzednia implementacja może zostać usunięta w przyszłości.
Edytuj 2:
W przypadku Rails 4 i concerns, polecam przeniesienie tego do concern.
# 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:02
Ryan Bates używa ładnego kodu w swoim Railscast na zaproszeniach beta . Tworzy to 40-znakowy ciąg alfanumeryczny.
Digest::SHA1.hexdigest([Time.now, rand].join)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-03 03:24:57
Jest kilka całkiem sprytnych sposobów, aby to zrobić, pokazanych w tym artykule:
Moja ulubiona lista to:
rand(36**8).to_s(36)
=> "uur0cj2h"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-04 21:23:00
Może to być późna odpowiedź, ale aby uniknąć użycia pętli, można również wywołać metodę rekurencyjnie. Wygląda i czuje się nieco czystszy dla mnie.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-03 13:33:13
Jeśli chcesz czegoś, co będzie wyjątkowe, możesz użyć czegoś takiego:
string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")
Wygeneruje to jednak ciąg 32 znaków.
Jest jednak inny sposób:
require 'base64'
def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end
Na przykład dla id jak 10000, wygenerowany token będzie jak "MTAwMDA=" (i można łatwo dekodować go dla id, po prostu zrobić
Base64::decode64(string)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-16 18:18:31
To może być pomocne:
SecureRandom.base64(15).tr('+/=', '0aZ')
Jeśli chcesz usunąć dowolny znak specjalny niż umieścić w pierwszym argumencie '+ / = 'i każdy znak umieścić w drugim argumencie' 0aZ ' i 15 jest długość tutaj .
I jeśli chcesz usunąć dodatkowe spacje i znak nowej linii, dodaj takie rzeczy jak:
SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")
Mam nadzieję, że to komuś pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-12 09:38:22
Spróbuj w ten sposób:
Od wersji Ruby 1.9, generowanie uuid jest wbudowane. Użyj funkcji SecureRandom.uuid
.
generowanie GUID w Ruby
To było dla mnie pomocne
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:14
Możesz user has_secure_token https://github.com/robertomiranda/has_secure_token
Jest naprawdę prosty w użyciu
class User
has_secure_token :token1, :token2
end
user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-04 15:51:29
Aby utworzyć właściwy, mysql, varchar 32 GUID
SecureRandom.uuid.gsub('-','').upcase
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-04 08:58:50
def generate_token
self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--")
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 16:36:27