Rails使用has_secure_password自动生成密码

时间:2013-04-04 22:20:45

标签: ruby-on-rails ruby-on-rails-4

我想在Rails 4.0应用中使用User时自动为has_secure_password生成密码(注意:这就是为什么没有attr_accessor)。

我有一个非常简单的User模型:

class User < ActiveRecord::Base
  has_secure_password
  validates :email, presence: true
end

我想知道如何在SecureRandom.hex(8)电话中使用before_save创建密码。我尝试添加before_save { self.password = SecureRandom.hex(8) }及其各种版本,但当我尝试将其保存在Rails控制台中时,它表示password为空。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

请尝试使用before_validation回调。 before_savevalidate之后运行,因此您的记录将始终无效。

还要考虑检查是否已设置密码。否则,您可以在每次更改记录时设置一个新的。

查找有关ActiveRecord callback chain here

的更多信息

答案 1 :(得分:0)

回调是一种有用的解决方案,但在您添加所需的复杂层时会使测试变得困难。

另一种方法是创建一个位于&#34;以上&#34;用户。我不认为这是最好的解决方案,但我发现它是有用的。请注意,此类继承自User类:

# user_with_default_password.rb
class UserWithDefaultPassword < User
  def initialize(options = {})
    random_password = SecureRandom.hex(8)

    options[:password] = random_password

    # If creating a user with confirmation requirements
    options[:password_confirmation] = random_password

    # Call User.new(options)
    super(options)
  end
end

用法:

user = UserWithDefaultPassword.new() # => user.password = "ajfladfjkf..."

这样做的好处是,您可以测试User和UserWithDefaultPassword,而不会强制通常会降低测试速度的回调。

此外,如果您只想使用User.new()而不是UserWithDefaultPassword.new(),则可以创建包含或不包含默认密码的用户。它提供了更大的灵活性和更好的测试。

更新时间:2014-04-21

另外,我建议将用于创建随机密码的代码等提取到一个单独的类中,您可以快速测试(不加载Rails框架)。以下是我最近为完成其中一些简单任务而编写的课程。

#==================================================
# Generates random/unique strings/tokens/IDs
# See: http://ruby-doc.org/stdlib-2.0.0/libdoc/securerandom/rdoc/SecureRandom.html
# See: http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-signin_success
#==================================================
class Generator
  require "securerandom"

  # General-purpose encryption using SHA1 instead of bcrypt; faster but LESS SECURE than bcrypt
  # (do not use for extremely sensitive data such as passwords)
  def self.encrypt(value)
    if value.nil? || value.empty?
      ""
    else
      Digest::SHA1.hexdigest(value.to_s)
    end
  end

  # Although a UUID would work as an auto-generated password,
  # it just seems more appropriate to make the password a random
  # string.
  def self.random_password
    SecureRandom.urlsafe_base64(32)
  end

  # Used as a random, unique token
  def self.uuid
    SecureRandom.uuid
  end

  # Returns random number as string for admin 2-step authentication
  def self.verification_code(length)
    value = ""

    if length.nil? || length.zero?
      length = 6
    elsif length > 20
      length = 20
    end

    length.times do |num|
      value += SecureRandom.random_number(10).to_s
    end

    value
  end
end

用法:Generator.random_password # => "abc123..."

大好处是您可以在不加载Rails框架的情况下测试随机密码的创建,从而节省3-4秒的加载时间。这主要是通过Rails 4.1来解决的,它使用Spring预加载你的应用程序进行测试,但是如果你不在Rails 4.1上(或者使用Spring gem),这是一个更好的解决方案。