【问题标题】:Rails: How to validate password from input if there is not password field in databaseRails:如果数据库中没有密码字段,如何从输入中验证密码
【发布时间】:2012-04-14 03:41:11
【问题描述】:

我的表格包含以下字段:emailpassword_hashsalt

在用户注册时,我想验证密码和密码确认,但我总是收到can't be blank 输入密码的错误。

这是我的模型:

attr_accessor :password

validates :password, :presence     => true,
                     :confirmation => true,
                     :length       => { :within => 6..40 }

我来宾我无法验证不是数据库的字段,但是如何对用户输入的密码进行验证?

我在数据库中没有密码字段,因为我加密了 password 输入,然后将其存储在 db password_hash 字段中。

编辑:

这是数据库表:

class CreateStudents < ActiveRecord::Migration
  def change
    create_table :students do |t|
      t.string :first_name
      t.string :last_name
      t.string :email
      t.string :password_hash
      t.string :salt

      t.boolean :activated

      t.timestamps
    end
  end
end

这是注册视图:

<%= form_for @student, url: {action: 'create'} do |form| %>

  <p style="font-size:smaller; color:red">
  <% @student.errors.messages.each do |att, msg| %>
    <%= msg[0] %><br>
  <% end %>
  <p>
  <%= form.label :first_name %><br>
  <%= form.text_field :first_name %>
  <p>
  <%= form.label :last_name %><br>
  <%= form.text_field :last_name %>
  <p>
  <%= form.label :email %><br>
  <%= form.text_field :email %>
  <p>
  <%= form.label :password %><br>
  <%= form.password_field :password %>
  <p>
  <%= form.label :password_confirmation %><br>
  <%= form.password_field :password_confirmation %>
  <p>
  <%= form.submit %>

<% end %>

这是控制器:

def sing_up
    @student = Student.new
    render 'sing_up'
end

def create
    @student = Student.new
    @student.first_name = params[:student][:first_name]
    @student.last_name = params[:student][:last_name]
    @student.email = params[:student][:email]

    @student.salt = BCrypt::Engine.generate_salt
    @student.password_hash = BCrypt::Engine.hash_secret(params[:student][:password], @student.salt)
    if @student.save
        redirect_to controller: 'singups', action: 'index'
    else
        render 'sing_up'
    end
end

最后,这是模特

class Student < ActiveRecord::Base
  attr_accessor :password
    validates :first_name, :length => { minimum: 3, message: "first_name" }
    validates :last_name, :length => { minimum: 3, message: "last_name" }
    validates :email, :presence => { message: 'email' },
              :format => { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/ , message: 'email format' },
              :uniqueness => { message: 'uniqueness?' }
    validates :password, :confirmation => { message: 'password' },
                         :length => { minimum: 6, message: 'password length' }
end

每次用户输入密码时,无论密码是什么,第一次验证 :confirmation =&gt; { message: 'password' } 都会失败。

如果我删除 validates :password 部分,一切正常,但用户输入的密码未经过验证。

【问题讨论】:

  • 请添加您的表单代码。我怀疑您在表单中使用了password_hash,而您什么时候应该使用password?是的,您可以验证任何字段,无论它是否是数据库列。
  • 我添加了更多信息,以便您查看。

标签: ruby-on-rails


【解决方案1】:

您正在验证用户的password 属性,但您从一开始就没有为其分配值。至少,您需要将其添加到您的控制器代码中:

@student.password = params[:student][:password]
@student.password_confirmation = params[:student][:password_confirmation]

然而,更简洁的方法是使用 mass-assignment - 去掉所有的 @student.xxx = yyy 并将其替换为:

@student = Studen.new(params[:student])

然后,将您的密码哈希方法移动到模型中,如果密码属性存在,则在每次保存之前自动触发它:

class User < ActiveRecord::Base
  # ...
  before_save :hash_password, :if => proc{ |u| !u.password.blank? }
  # ....

  protected

  def hash_password
    self.salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password, salt)
  end
end

这样你不必在控制器中做任何事情,但是:

def create
  @student = Student.new(params[:student])
  if @student.save
    redirect_to controller: 'singups', action: 'index'
  else
    render 'sing_up'
  end
end

并在您的模型中拥有所有其他逻辑,它所属的位置。

编辑:为了使批量分配能够与最新版本的 Rails 3 一起使用,您需要像 attr_accessible 那样设置要分配的属性,如下所示:

class Student < ActiveRecord::Base
  # ...
  attr_accessible :first_name, :last_name, :email, :password # but NOT the hash or salt!!

end

【讨论】:

    【解决方案2】:

    您应该从头开始查看 Railscast 处理身份验证,所有内容都在此处进行了解释http://railscasts.com/episodes/250-authentication-from-scratch

    这里有更新的演员表http://railscasts.com/episodes/250-authentication-from-scratch-revised,但您需要订阅才能观看(非常值得 IMO)

    【讨论】:

    • 这是我的想法,但我不知道我在哪里做错了
    【解决方案3】:

    需要将用户输入的密码转换成加密值,然后将加密后的值与password_hash中的值进行比较,看是否匹配。这就是您验证用户是否是正确用户的方式。如果您的模型没有密码字段(不应该)并不重要,因为您不直接比较密码中的值。

    有不同的加密方法,但重要的是您如何将原始密码首先加密到 password_hash 中(您是如何生成“password_hash”的?)。使用相同的方法检查新密码提交。

    【讨论】:

    • 我不确定你说得对不对。我需要验证“登录”时输入的密码,而不是登录时输入的密码
    【解决方案4】:

    您可以使用自定义验证来检查密码和密码确认。

    class User< ActiveRecord::Base
      attr_accessor :password, :password_confirmation 
      validate :valid_password
    
      def valid_password
        if password.blank? || password_confirmation.blank?
          errors.add(:password, 'password must not be blank')
        end
    
        if password != password_confirmation
          errors.add(:password, 'password and confirmation does not match')
        end
      end
    
    end
    

    这样,它会检查密码和确认是否同时存在。

    【讨论】:

    • 他已经在使用内置的验证了,他首先不是问如何验证,而是为什么在注册时验证密码。
    猜你喜欢
    • 2016-01-16
    • 2022-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多