哈希密码未保存在密码列中
Hash password not saved in the password column
我试图在注册时将哈希密码存储在我的 users
table 中。请看我的代码:
users_controller.rb
def login
@title = 'Login'
#render layout: 'login'
end
def create_login
user = User.authenticate(params[:user][:username], params[:user][:password])
if user
log_in user
redirect_to '/admin'
else
flash[:danger] = 'Invalid email/password combination' # Not quite right!
redirect_to :back
end
end
def register
@user = User.new
@title = 'Register'
end
def create_register
params[:user][:uniq_id] = generate_uniq
@user = User.new(create_user_params)
#raise @user.inspect
respond_to do |format|
if @user.save
format.html { redirect_to :success, success: 'Registration was successfully created.' }
format.json { redirect_to :register, status: :created, location: @users }
else
format.html { render :register }
format.json { render json: @users.errors, status: :unprocessable_entity }
end
end
end
private
def create_user_params
params.require(:user).permit(:uniq_id, :name, :username, :email, :password, :password_confirmation, :password_salt, :dob, :address)
end
register.html.erb
<%= form_tag("/register", method: "post") do %>
<%#= form_tag(@user) do |f| %>
<% if @user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= text_field :user, :name, placeholder:'NAME', required: true %>
<div style="position: relative;">
<span id="chk-username" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :username, placeholder:'USERNAME', 'data-validate':"/users/check_username", required: true %>
</div>
<div style="position: relative;">
<span id="chk-email" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :email, placeholder:'EMAIL', 'data-validate':"/users/check_email", required: true %>
</div>
<%= password_field :user, :password, placeholder:'PASSWORD', required: true %>
<%= password_field :user, :password_confirmation, placeholder:'CONFIRM PASSWORD', required: true %>
<div class="submit">
<input type="submit" value="REGISTER" >
<input type="button" onclick="location.href = '<%= request.base_url %>/login'" value="LOGIN" >
</div>
<p><a href="#">Forgot Password ?</a></p>
<% end %>
user.rb
class User < ActiveRecord::Base
#has_secure_password
attr_accessor :password
before_save :encrypt_password
validates :name, presence: true
validates :name, length: { minumum:2, maximum: 30 }
validates :password, :presence =>true,
:length => { :minimum => 6, :maximum => 40 },
:confirmation =>true
validates :username, :presence => true,
:uniqueness => { :case_sensitive => false }
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
def self.authenticate(input_username, input_password)
user = find_by_username(input_username)
if user && user.password == BCrypt::Engine.hash_secret(input_password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
routes.rb
get 'register' => 'users#register'
post 'register' => 'users#create_register'
这是我的数据库 table。
users.sql(自定义table)
+----+----------+------------+-----------+----------------+
| id | name | username | password | password_salt |
+----+----------+------------+-----------+----------------+
| 1 | chinmay | chinu | NULL |afWDt.. |
| 2 | sanjib | sanjib | NULL |aDyMr.. |
+----+----------+------------+-----------+----------------+
我在 password
列中得到 NULL
值。请帮助我,让我知道我的代码中的错误所在。
你的主要错误是你正在使用 attr_accessor :password
为密码属性创建一个 getter/setter 覆盖 ActiveRecord 从数据库创建的 getter 和 setter架构。
然而,您的整个密码加密方法存在缺陷 - 您应该将 password
作为纯粹的 virtual attribute 并将您的数据库列命名为 password_digest
或 encrypted_password
.
除非出于纯粹的学习目的,否则应该使用 Rails 提供的 has_secure_password
宏,而不是重新发明密码加密轮并被黑客攻击。
1。向用户添加 password_digest
列:
rails g migration AddPassWordDigestToUser password_digest:string:index
您可能想要删除 password_salt
列,因为它未被 ActiveModel::SecurePassword
使用。
class AddPassWordDigestToUser < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
add_index :users, :password_digest
remove_column :users, :password_salt
remove_column :users, :password
end
end
2。将 has_secure_password
添加到用户模型:
class User < ActiveRecord::Base
has_secure_password
end
3。 RESTful 路线
您可能想要更正您的路线,使它们以资源为导向而不是以行动为导向,并遵循 rails 约定:
GET /registrations/new registations#new - sign up form
POST /registrations registations#create - create user
GET /sessions/new sessions#new - sign in form
POST /sessions sessions#create - sign in user
您可以设置路线:
resources :registrations, only: [:new, :create]
resources :sessions, only: [:new, :create]
参见 Rails Routing from the Outside In。
4。绑定表单和控制器。
您正在正确设置控制器,但是您的表单未绑定到您在控制器中创建的 @user
模型实例。
这意味着用户输入的值在表单提交失败后消失。
还要注意变量的复数化和命名!您不一致地使用 @user
和 @users
。在这种情况下 @users
将始终为 nil 并导致错误。
app/controllers/registrations_controller.rb:
class RegistationsController < ApplicationController
def new
@user = User.new
end
def create
# Use a block instead of messing with the incoming params.
@user = User.new(user_params) do |u|
u.uniq_id = generate_uniq
end
if @user.save
respond_to do |format|
format.html { redirect_to root_path, success: "Welcome #{@user.email}" }
format.json { status: :created, location: @user }
end
else
respond_to do |format|
format.html { redirect_to :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
app/views/registrations/new.html.erb:
<%= form_for(@user, url: registrations_path) do |f| %>
<div class="row">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="row">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="row">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<% end %>
我试图在注册时将哈希密码存储在我的 users
table 中。请看我的代码:
users_controller.rb
def login
@title = 'Login'
#render layout: 'login'
end
def create_login
user = User.authenticate(params[:user][:username], params[:user][:password])
if user
log_in user
redirect_to '/admin'
else
flash[:danger] = 'Invalid email/password combination' # Not quite right!
redirect_to :back
end
end
def register
@user = User.new
@title = 'Register'
end
def create_register
params[:user][:uniq_id] = generate_uniq
@user = User.new(create_user_params)
#raise @user.inspect
respond_to do |format|
if @user.save
format.html { redirect_to :success, success: 'Registration was successfully created.' }
format.json { redirect_to :register, status: :created, location: @users }
else
format.html { render :register }
format.json { render json: @users.errors, status: :unprocessable_entity }
end
end
end
private
def create_user_params
params.require(:user).permit(:uniq_id, :name, :username, :email, :password, :password_confirmation, :password_salt, :dob, :address)
end
register.html.erb
<%= form_tag("/register", method: "post") do %>
<%#= form_tag(@user) do |f| %>
<% if @user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= text_field :user, :name, placeholder:'NAME', required: true %>
<div style="position: relative;">
<span id="chk-username" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :username, placeholder:'USERNAME', 'data-validate':"/users/check_username", required: true %>
</div>
<div style="position: relative;">
<span id="chk-email" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :email, placeholder:'EMAIL', 'data-validate':"/users/check_email", required: true %>
</div>
<%= password_field :user, :password, placeholder:'PASSWORD', required: true %>
<%= password_field :user, :password_confirmation, placeholder:'CONFIRM PASSWORD', required: true %>
<div class="submit">
<input type="submit" value="REGISTER" >
<input type="button" onclick="location.href = '<%= request.base_url %>/login'" value="LOGIN" >
</div>
<p><a href="#">Forgot Password ?</a></p>
<% end %>
user.rb
class User < ActiveRecord::Base
#has_secure_password
attr_accessor :password
before_save :encrypt_password
validates :name, presence: true
validates :name, length: { minumum:2, maximum: 30 }
validates :password, :presence =>true,
:length => { :minimum => 6, :maximum => 40 },
:confirmation =>true
validates :username, :presence => true,
:uniqueness => { :case_sensitive => false }
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
def self.authenticate(input_username, input_password)
user = find_by_username(input_username)
if user && user.password == BCrypt::Engine.hash_secret(input_password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
routes.rb
get 'register' => 'users#register'
post 'register' => 'users#create_register'
这是我的数据库 table。
users.sql(自定义table)
+----+----------+------------+-----------+----------------+
| id | name | username | password | password_salt |
+----+----------+------------+-----------+----------------+
| 1 | chinmay | chinu | NULL |afWDt.. |
| 2 | sanjib | sanjib | NULL |aDyMr.. |
+----+----------+------------+-----------+----------------+
我在 password
列中得到 NULL
值。请帮助我,让我知道我的代码中的错误所在。
你的主要错误是你正在使用 attr_accessor :password
为密码属性创建一个 getter/setter 覆盖 ActiveRecord 从数据库创建的 getter 和 setter架构。
然而,您的整个密码加密方法存在缺陷 - 您应该将 password
作为纯粹的 virtual attribute 并将您的数据库列命名为 password_digest
或 encrypted_password
.
除非出于纯粹的学习目的,否则应该使用 Rails 提供的 has_secure_password
宏,而不是重新发明密码加密轮并被黑客攻击。
1。向用户添加 password_digest
列:
rails g migration AddPassWordDigestToUser password_digest:string:index
您可能想要删除 password_salt
列,因为它未被 ActiveModel::SecurePassword
使用。
class AddPassWordDigestToUser < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
add_index :users, :password_digest
remove_column :users, :password_salt
remove_column :users, :password
end
end
2。将 has_secure_password
添加到用户模型:
class User < ActiveRecord::Base
has_secure_password
end
3。 RESTful 路线
您可能想要更正您的路线,使它们以资源为导向而不是以行动为导向,并遵循 rails 约定:
GET /registrations/new registations#new - sign up form
POST /registrations registations#create - create user
GET /sessions/new sessions#new - sign in form
POST /sessions sessions#create - sign in user
您可以设置路线:
resources :registrations, only: [:new, :create]
resources :sessions, only: [:new, :create]
参见 Rails Routing from the Outside In。
4。绑定表单和控制器。
您正在正确设置控制器,但是您的表单未绑定到您在控制器中创建的 @user
模型实例。
这意味着用户输入的值在表单提交失败后消失。
还要注意变量的复数化和命名!您不一致地使用 @user
和 @users
。在这种情况下 @users
将始终为 nil 并导致错误。
app/controllers/registrations_controller.rb:
class RegistationsController < ApplicationController
def new
@user = User.new
end
def create
# Use a block instead of messing with the incoming params.
@user = User.new(user_params) do |u|
u.uniq_id = generate_uniq
end
if @user.save
respond_to do |format|
format.html { redirect_to root_path, success: "Welcome #{@user.email}" }
format.json { status: :created, location: @user }
end
else
respond_to do |format|
format.html { redirect_to :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
app/views/registrations/new.html.erb:
<%= form_for(@user, url: registrations_path) do |f| %>
<div class="row">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="row">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="row">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<% end %>