Generowanie przewodników w Rubim

142

Mam problem, który można naprawdę łatwo rozwiązać za pomocą Guidów.

W szczególności w przypadku procedury resetowania hasła chciałbym wysłać token Guid na e-mail użytkownika i poprosić go o zresetowanie hasła za pomocą tokena. Ponieważ przewodniki są unikalne, jest to dość bezpieczne i oszczędza mi wysyłania haseł e-mailem, co jest ryzykowne.

Zauważyłem, że jest jeden klejnot Guid dla Ruby; ale wygląda na dość stary i zapisuje rzeczy w systemie plików.

Czy ktoś zna inne klejnoty, które mogą stworzyć globalnie unikalny identyfikator?

Wiem, że mogę po prostu wrócić do:

(0..16).to_a.map{|a| rand(16).to_s(16)}.join 

Ale tak naprawdę nie wygląda na właściwy identyfikator GUID ...

Sam Saffron
źródło
1
Używanie takiego losowego ciągu nie byłoby całkiem poprawne; pewne bity w UUID określają wariant i wersję. W przypadku losowego identyfikatora UUID prawdopodobnie potrzebujesz wariantu 2 (RFC 4122) i wersji 4, w którym to przypadku 6 określone bity muszą być ustawione na prawidłowe wartości.
jtpereyda
1
Tak, @dafrazzman ma rację. Losowe łączenie czegoś, co „przypomina UUID”, nie gwarantuje niepowtarzalności. Chociaż żaden UUID nie jest naprawdę gwarantowany, zbudowanie takiego z liczbami losowymi jest O WIELE bardziej podatne na kolizje i nie może być godne oznaczenia „UUID”. Zdecydowanie wybierz SecureRandom.uuid!
dooleyo

Odpowiedzi:

312

Od Ruby 1.9 generowanie uuid jest wbudowane. Użyj SecureRandom.uuidfunkcji.

Na przykład:

require 'securerandom'
SecureRandom.uuid # => "96b0a57c-d9ae-453f-b56f-3b154eb10cda"
J _
źródło
5
SecureRandom.uuid generuje losowy UUID, więc nie ma gwarancji, że jest unikalny. Jeśli chcesz po prostu losowego ciągu, który prawdopodobnie jest unikalny, możesz go użyć. Jeśli jednak chcesz czegoś, co na pewno jest unikalne, musisz użyć czegoś, co zawiera adres MAC, znacznik czasu i tak dalej.
Mike Dotterer
23
Aby zaoszczędzić trochę czasu na wyszukiwaniu, musisz wymagać „securerandom”
Jesse Shieh,
8
Nie ma gwarancji, że będzie wyjątkowy, ale w większości praktycznych celów można bezpiecznie założyć, że jest wyjątkowy. Zobacz: stackoverflow.com/questions/2977593/…
Jesse Shieh
jeśli SecureRandom.uuid postępuje zgodnie z RFC 4122, zgodnie z dokumentacją, czy nie oznacza to, że ma pole znacznika czasu? Poza współbieżnością, czy nie oznacza to unikalności?
Michael K Madison,
@MichaelKMadison AFAIK Ruby używa wariantu „v4” RFC 4122, który nie używa sygnatury czasowej, więc szansa na kolizję nie jest w rzeczywistości zerowa - ale w praktyce równie dobrze może być
Edd Morgan
38

Jak tworzyć małe, unikalne tokeny w Rubim

>> require 'digest'
=> []
>> Digest::SHA1.hexdigest("some-random-string")[8..16]
=> "2ebe5597f"

>> SecureRandom.base64(8).gsub("/","_").gsub(/=+$/,"")
=> "AEWQyovNFo0" 

>> rand(36**8).to_s(36)
=> "uur0cj2h"
Simone Carletti
źródło
35

Używamy UUIDTools i nie mamy z tym żadnych problemów.

Avdi
źródło
2
„uuidtools” działa, nawet jeśli system nie ma adresu MAC. „uuid” w tym przypadku zawodzi.
grefab
3
W przeciwieństwie do klejnotu uuid, uuidtools nie przechowuje pliku stanu. Problemy z uprawnieniami w pliku stanu sprawiają, że uuid gem jest nieco niewygodny w użyciu dla wielu użytkowników.
Wayne Conrad
1
Wygląda na to, że narzędzia UUID nie są już obsługiwane. Nie było żadnego zobowiązania do repozytorium github od ponad 2 lat
Sudhanshu Mishra
22

Czy spojrzałeś na UUIDTools ?

Narzędzie UUIDTools zostało zaprojektowane jako prosta biblioteka do generowania dowolnego z różnych typów identyfikatorów UUID (lub identyfikatorów GUID, jeśli wolisz je tak nazywać). W miarę możliwości jest zgodny z RFC 4122.

Andrew Hare
źródło
16

Google udostępnia następującą bibliotekę Ruby:

http://raa.ruby-lang.org/project/ruby-guid/

Również na http://www.ruby-forum.com/topic/99262 mówią, że możesz zainstalować gem (wykonaj gem uuidw wierszu poleceń, aby go zainstalować), a następnie wykonaj

gem 'uuid'
puts UUID.new

w kodzie, aby wyświetlić nowy identyfikator UUID.

(Podpowiedź: wyszukałem w Google guid ruby )

Marc W.
źródło
thx Widziałem to, ale jest bardzo stare, po prostu szukasz czegoś aktywnego, jak niedawny klejnot?
Lance Pollard
A co z klejnotem uuid, który dodałem do mojej odpowiedzi? A może to ten, o którym mówiłeś?
Marc W
5
To dziwne ... Wygooglowałem również „guid ruby” i otrzymałem tylko ten post :-P
Jason Whitehorn,
3

Aby utworzyć poprawny identyfikator GUID mysql, varchar 32

SecureRandom.uuid.gsub('-','').upcase
Aaron Henderson
źródło
LubSecureRandom.hex.upcase
Daniel Antonio Nuñez Carhuayo
3

Mała aktualizacja odpowiedzi Simone Carletti:

SecureRandom.base64 (8) .gsub („/”, „_”). Gsub (/ = + $ /, „”)

=> „AEWQyovNFo0”

można zastąpić:

SecureRandom.urlsafe_base64 (8)

Алексей Лещук
źródło
1

Podczas programowania późno w nocy wpadłem na następujące rozwiązanie (bazujące na Simone) do generowania unikalnego GUID w Railsach. Nie jestem z tego dumny, ale działa całkiem nieźle.

while Order.find_by_guid(guid = rand(36**8).to_s(36).upcase).present?; end
robotmoże
źródło
2
Mam nadzieję, że pamiętałeś o indeksowaniu swojej kolumny z przewodnikiem tamtej nocy
nurettin
0

Kiedy użyłem klejnotów uuid zalecanych w tym pytaniu, nikt nie może wygenerować unikalnego i losowego UUID. Moją odpowiedzią jest obejście, jeśli będziemy mieli klejnot później, aby spełnić żądanie, lepiej użyj klejnotu w Rubim.

Próbuję większości polecanych klejnotów uuid w tym pytaniu, ale nikt mnie nie satysfakcjonuje, potrzebujemy unikalnego i losowego uuidu. Bezpośrednio uruchamiam polecenie systemowe uuidgenw języku ruby ​​i podoba mi się wynik i udostępniam tutaj.

puts `uuidgen`
8adea17d-b918-43e0-b82f-f81b3029f688
puts `uuidgen`
6a4adcce-8f64-41eb-bd7e-e65ee6d11231
puts `uuidgen`
51d5348b-8fc3-4c44-a6f7-9a8588d7f08a
puts `uuidgen`
332a0fa3-7b07-41e1-9fc8-ef804a377e4e

w porównaniu z uuidklejnotem poznasz różnicę.

irb(main):003:0> uuid.generate
=> "40cdf890-ebf5-0132-2250-20c9d088be77"
irb(main):004:0> uuid.generate
=> "4161ac40-ebf5-0132-2250-20c9d088be77"

Środowisko testowe to środowisko Linux i Mac OS.

BMW
źródło
2
a w puts `...`zasadzie wykonuje wywołanie systemowe, uuidgen(3)które kończy się niepowodzeniem na żadnej innej platformie niż Linux, dodaje ekstremalne ilości czasu wykonania i ogólnie jest naprawdę sprzeczną z intuicją praktyką kodowania. Dlaczego miałbyś wybrać taką metodę?
Dwight Spencer,
1
@DwightSpencer Myślę, że jesteśmy w innym obszarze i mamy inny cel. To, co cię obchodzi, w ogóle nie dotyczy mnie, takich jak czas wykonywania, szeroki zakres systemów operacyjnych, migracje kodu. Obawiam się, że kod może działać w systemie Mac OS lub w głównym strumieniu Linux i uzyskać właściwy wynik, którego potrzebuję. Oczywiście, jeśli możesz wypracować sposób w Rubim i uzyskać taki sam wynik jak polecenie uuidgen, z przyjemnością go używam. Ale do tej pory nie znalazłem żadnego.
BMW,
1
Zarówno @J_, jak i @ simone-carletti wskazały już lepszą drogę w tym poście. Dla jednego sugerowałbym, SecureRandomponieważ wykonuje tę samą funkcję w tej samej metodzie, uuidgenale w przeciwieństwie do uuidgenużycia blokowania / dev / random SecureRandomużywa tylko biblioteki openssl, a następnie spada do dev / urandom, a następnie w końcu / dev / random w próbach wykonania nieblokujące generowanie randomizacji.
Dwight Spencer
0

Oto technika Neet, której nauczyłem się z JavaScript:

def uuid
    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".gsub("x") do
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand(36)]
    end
end

Chociaż w bardziej `` rubinowy '' sposób można też zrobić:

def uuid
    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".gsub("x") do
        rand(16).to_s(16)
    end
end
Sancarn
źródło