ruby-on-rails - crear - rails api authentication
¿La mejor forma de crear un token único en Rails? (10)
Esto es lo que estoy usando. El token no tiene necesariamente que ser escuchado para adivinar, es más como un identificador de url corto que cualquier otra cosa, y quiero que sea breve. He seguido algunos ejemplos que he encontrado en línea y en el caso de una colisión, creo que el código siguiente recreará el token, pero no estoy muy seguro. Tengo curiosidad por ver mejores sugerencias, sin embargo, ya que esto se siente un poco difícil en los bordes.
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
Mi columna de base de datos para el token es un índice único y también estoy usando validates_uniqueness_of :token
en el modelo, pero porque estos se crean automáticamente en lotes en función de las acciones de un usuario en la aplicación (hacen un pedido y compran los tokens, esencialmente ), no es factible que la aplicación arroje un error.
También podría, supongo, reducir la posibilidad de colisiones, agregar otra cadena al final, algo generado en función del tiempo o algo así, pero no quiero que el token sea demasiado largo.
Esta podría ser una respuesta tardía, pero para evitar el uso de un bucle también puede llamar al método recursivamente. Se ve y se siente un poco más limpio para mí.
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
Esto puede ser útil:
SecureRandom.base64(15).tr(''+/='', ''0aZ'')
Si desea eliminar cualquier carácter especial, coloque el primer argumento ''+ / ='' y cualquier carácter puesto en el segundo argumento ''0aZ'' y 15 es la longitud aquí.
Y si desea eliminar los espacios adicionales y el nuevo carácter de línea, agregue cosas como:
SecureRandom.base64(15).tr(''+/='', ''0aZ'').strip.delete("/n")
Espero que esto ayude a cualquiera.
Hay algunas maneras bastante hábiles de hacer esto demostrado en este artículo:
Mi lista favorita es esta:
rand(36**8).to_s(36)
=> "uur0cj2h"
Para crear un GUID apropiado, mysql, varchar 32
SecureRandom.uuid.gsub(''-'','''').upcase
Pruebe de esta manera:
A partir de Ruby 1.9, la generación de uuid está incorporada. Use la función SecureRandom.uuid
.
Generando Guids en Ruby
Esto fue útil para mí
Ryan Bates usa un poco de código en sus invitaciones de Railscast . Esto produce una cadena alfanumérica de 40 caracteres.
Digest::SHA1.hexdigest([Time.now, rand].join)
Si quieres algo que sea único, puedes usar algo como esto:
string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")
sin embargo, esto generará una cadena de 32 caracteres.
Sin embargo, hay otra forma:
require ''base64''
def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end
por ejemplo, para id como 10000, el token generado sería como "MTAwMDA =" (y usted puede decodificarlo fácilmente para el id, simplemente haga
Base64::decode64(string)
puedes usar has_secure_token https://github.com/robertomiranda/has_secure_token
es realmente simple de usar
class User
has_secure_token :token1, :token2
end
user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"
- Actualización -
A partir del 9 de enero de 2015, la solución ahora se implementa en la implementación de token seguro de Rails 5 ActiveRecord .
- Carriles 4 y 3 -
Solo para referencia futura, crear un token aleatorio seguro y garantizar su exclusividad para el modelo (cuando se usa Ruby 1.9 y 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
Editar:
@kain sugirió, y acepté, reemplazar el begin...end..while
loop do...break unless...end
en esta respuesta porque la implementación anterior podría eliminarse en el futuro.
Editar 2:
Con Rails 4 y las preocupaciones, recomendaría mover esto a la preocupación.
# 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
def generate_token
self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--")
end