webentwicklung-frage-antwort-db.com.de

Der beste Weg, ein einzigartiges Token in Rails zu erstellen?

Hier ist was ich benutze. Das Token muss nicht unbedingt gehört werden, um zu erraten, es ist eher eine kurze URL-Kennung als alles andere, und ich möchte es kurz halten. Ich bin einigen Beispielen gefolgt, die ich online gefunden habe, und im Falle einer Kollision ich denke der Code unten wird das Token neu erstellen, aber ich bin mir nicht sicher. Ich bin jedoch gespannt auf bessere Vorschläge, da sich dies an den Rändern etwas rau anfühlt.

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

Meine Datenbankspalte für das Token ist ein eindeutiger Index, und ich verwende auch validates_uniqueness_of :token für das Modell. Da diese jedoch stapelweise auf der Grundlage der Benutzeraktionen in der App erstellt werden (sie bestellen eine Bestellung und kaufen im Wesentlichen die Token), Es ist nicht möglich, dass die App einen Fehler ausgibt.

Ich denke auch, um die Wahrscheinlichkeit von Kollisionen zu verringern, füge ich am Ende eine andere Zeichenkette hinzu, etwas, die auf der Zeit basiert oder so ähnlich, aber ich möchte nicht, dass der Token zu lang wird.

147
Slick23

- Update -

Ab dem 9. Januar 2015 . ist die Lösung nun in Rails 5 ActiveRecord's implementiert sichere Token-Implementierung .

- Rails 4 & 3 -

Nur zum späteren Nachschlagen, Erstellen eines sicheren zufälligen Tokens und Sicherstellen, dass es für das Modell eindeutig ist (bei Verwendung von Ruby 1.9 und 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

Bearbeiten:

@ kain schlug vor und ich stimmte zu, begin...end..while in dieser Antwort durch loop do...break unless...end zu ersetzen, da frühere Implementierungen in Zukunft möglicherweise entfernt werden.

Edit 2:

Bei Rails 4 und Concern würde ich empfehlen, dies in Concern zu verschieben.

# 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
326
Krule

Ryan Bates verwendet in seinem Railscast ein nettes bisschen Code für Beta-Einladungen . Dies erzeugt eine alphanumerische Zeichenfolge mit 40 Zeichen.

Digest::SHA1.hexdigest([Time.now, Rand].join)
48
Nate Bird

In diesem Artikel werden einige recht glatte Methoden gezeigt:

https://web.archive.org/web/20121026000606/http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-Ruby

Mein Favorit ist folgender:

Rand(36**8).to_s(36)
=> "uur0cj2h"
29
coreyward

Dies kann eine späte Antwort sein, aber um die Verwendung einer Schleife zu vermeiden, können Sie die Methode auch rekursiv aufrufen. Es sieht aus und fühlt sich für mich etwas sauberer an.

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
27
Marius Pop

Wenn Sie etwas Einzigartiges wünschen, können Sie Folgendes verwenden:

string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")

dies erzeugt jedoch eine Zeichenfolge mit 32 Zeichen.

Es gibt jedoch einen anderen Weg:

require 'base64'

def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end

zum Beispiel für eine ID wie 10000 wäre das generierte Token wie "MTAwMDA =" (und Sie können es einfach für die ID dekodieren, machen Sie einfach

Base64::decode64(string)
17
Esse

Das kann hilfreich sein:

SecureRandom.base64(15).tr('+/=', '0aZ')

Wenn Sie ein Sonderzeichen entfernen möchten, geben Sie im ersten Argument '+/=' ein, und in das zweite Argument '0aZ' und 15 wird die Länge eingefügt.

Und wenn Sie die zusätzlichen Leerzeichen und das neue Linienzeichen entfernen möchten, fügen Sie die folgenden Dinge hinzu:

SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")

Ich hoffe, das hilft jedem.

14
Vik

Versuchen Sie es so:

Ab Ruby 1.9 ist die Erzeugung von Uuids integriert. Verwenden Sie die SecureRandom.uuid-Funktion.
Erstellen von Hilfslinien in Ruby

Das war hilfreich für mich

sie können Benutzer has_secure_token https://github.com/robertomiranda/has_secure_token

ist wirklich einfach zu bedienen

class User
  has_secure_token :token1, :token2
end

user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"
6
user2627938

Zum Erstellen einer ordnungsgemäßen mysql, varchar 32-GUID

SecureRandom.uuid.gsub('-','').upcase
4
Aaron Henderson
def generate_token
    self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--")
end
1
miosser

Ich denke, das Token sollte wie ein Passwort behandelt werden. Daher sollten sie in der DB verschlüsselt sein.

Ich mache so etwas, um ein einzigartiges neues Token für ein Modell zu generieren:

key = ActiveSupport::KeyGenerator
                .new(Devise.secret_key)
                .generate_key("put some random or the name of the key")

loop do
  raw = SecureRandom.urlsafe_base64(nil, false)
  enc = OpenSSL::HMAC.hexdigest('SHA256', key, raw)

  break [raw, enc] unless Model.exist?(token: enc)
end
0
cappie013