我正在创建一个在注册过程中完美运行的用户登录。当用户填写“注册”表单并提交时,会按照预期将用户登录到其帐户中。但是当我注销并尝试使用登录表单再次登录时,它将不会对用户进行身份验证,即使凭据确实是正确的。
我的应用有三种不同类型的用户角色:播放器,所有者和 admin 。我相信它与我在注册期间将角色持久保存到用户时有关,这导致登录时的身份验证无法正常工作。
User.rb
class User < ActiveRecord::Base
# Roles
enum role: [:player => 0, :owner => 1, :admin => 2]
after_initialize :set_default_role, :if => :new_record?
# Validations
validates :username, presence: true
validates :password, presence: true
# validates_confirmation_of :password
before_save :encrypt_password
attr_accessor :password_confirmation, :role_type
def set_default_role
self.role ||= :player
end
def encrypt_password
self.password_salt = BCrypt::Engine.generate_salt
self.password = BCrypt::Engine.hash_secret(password, self.password_salt)
end
def self.authenticate(username, password)
user = User.where(username: username).first
if user && user.password == BCrypt::Engine.hash_secret(password, user.password_salt)
return user
else
return nil
end
end
end
users_controller.rb
class UsersController < ApplicationController
include ApplicationHelper
before_filter :current_user
def index
@user = User.new
end
# Display the SignUp Form
def new
@user = User.new
end
def create
@user = User.new(user_params)
# Save to the database
if @user.save
flash[:notice] = "Welcome, #{@user.username}!"
session[:user_id] = @user.id
# Check if they selected Owner checkbox
if user_params[:role_type].to_i == 1
@user.owner!
else
@user.player!
end
redirect_accordingly(@user)
else
flash[:alert] = "Some of the info you provided needs tweaking."
render :new
end
end
private
def user_params
params.require(:user).permit(:username, :password, :password_confirmation, :email, :role_type)
end
end
sessions_controller.rb - 处理登录的位置
class SessionsController < ApplicationController
include ApplicationHelper
#Login Process
def create
# authenticate method returns nil when a role is
# persisted to the user during registration
# e.g. when @user.owner! is used in the UsersController#create
if @user = User.authenticate(params[:username], params[:password])
flash[:notice] = "Welcome back, #{@user.username}!"
session[:user_id] = @user.id
redirect_accordingly(@user)
else
flash.now[:alert] = "Invalid username or password. #{@user}"
render :new
end
end
#Login Form
def new
@user = User.new
end
#Log Out
def destroy
session.delete(:user_id)
redirect_to root_path, :notice => "You have logged out."
end
end
在UsersController #create中,条件if
语句在注册期间向用户保留角色,例如@user.owner!
或@user.player!
,因为它将正确的整数添加到数据库role
1}}列,并记录新用户。
我退出后,尝试使用登录表单重新登录用户,但是没有成功。 User.authenticate(params[:username], params[:password])
方法返回nil
。所以我开始在rails控制台中剖析方法:
假设我在我的数据库中有这个例子:
+----+--------------+--------------------------------------------------------------+-------------------------------+-------------------------+---------------------+---------------------+------+
| id | username | password | password_salt | email | created_at | updated_at | role |
+----+--------------+--------------------------------------------------------------+-------------------------------+-------------------------+---------------------+---------------------+------+
| 27 | grahamsutt12 | $2a$10$T6cRC/F0NQOeHhorQfxLjOkVQfOPwvUU0eEbKhlS.Pa4aD2TRvxvy | $2a$10$T6cRC/F0NQOeHhorQfxLjO | graham@gmail.com | 2015-05-22 01:19:24 | 2015-05-22 01:19:24 | 0 |
| 28 | mike12 | $2a$10$S7vOdf43uhMU0/RUOc/vv.VIJzaGetvnB88kt/IzCEuFK1JgZBzBO | $2a$10$S7vOdf43uhMU0/RUOc/vv. | mike@gmail.com | 2015-05-22 02:07:33 | 2015-05-22 02:07:33 | 1 |
+----+--------------+--------------------------------------------------------------+-------------------------------+-------------------------+---------------------+---------------------+------+
#password for mike12 is "mikerton"
# Returns incorrectly
User.authenticate("mike12", "mikerton")
User Load (59.0ms) SELECT `users`.* FROM `users` WHERE `users`.`username` = 'mike12' ORDER BY `users`.`id` ASC LIMIT 1
=> nil
### Now, diving in to the authenticate method ###
# Returns correctly
user = User.where(username: "mike12").first
User Load (56.9ms) SELECT `users`.* FROM `users` WHERE `users`.`username` = 'mike12' ORDER BY `users`.`id` ASC LIMIT 1
=> #<User id: 28, username: "mike12", password: "$2a$10$S7vOdf43uhMU0/RUOc/vv.VIJzaGetvnB88kt/IzCEu...", password_salt: "$2a$10$S7vOdf43uhMU0/RUOc/vv.", email: "mike@gmail.com", created_at: "2015-05-22 02:07:33", updated_at: "2015-05-22 02:07:33", role: 1>
#!!! Passwords are different from each other? !!!#
BCrypt::Engine.hash_secret("mikerton", user.password_salt)
=> "$2a$10$S7vOdf43uhMU0/RUOc/vv.rus89JjBDd2Mna6aRD8xgkMEO3FEPzK"
user.password
=> "$2a$10$S7vOdf43uhMU0/RUOc/vv.VIJzaGetvnB88kt/IzCEuFK1JgZBzBO"
正如您在两次加密中vv.
后看到的密码不同。
此外,我应该在SignUp期间不使用@user.owner
或@user.player
时添加加密为相同,但是用户的角色出现在1
。
为什么这会改变密码加密?如何使用enum
使用“Rails方式”正确地将角色存储在数据库中?
答案 0 :(得分:2)
所以我做的方式如下:
在我的模型中,定义我的枚举:
<%= f.label :role, "Account Type", class: "label-hidden" %>
<%= f.select :role, options_for_user_role %>
然后在我的用户表单中,定义角色:
def options_for_user_role
[
['Select Account Type', ' '],
['Player','player'],
['Owner','owner']
]
end
然后在我的用户帮助中,我已经定义了选项。基本上,您需要发送字符串而不是整数。
def user_params
params.require(:user).permit(:username, :password, :password_confirmation, :email, :role)
end
然后在您的控制器中,确保将角色添加到您允许的参数
# Check if they selected Owner checkbox
if user_params[:role_type].to_i == 1
@user.owner!
else
@user.player!
end
然后在您的用户控制器创建方法中,如果role_type为1或0,则不需要检查代码,您可以将其删除(不需要):
validates :role, presence: true, inclusion: { in: ["player", "owner", "admin"] }
我还在我的用户模型中添加了一些验证,以确保用户具有角色:
if !@user.admin? && @user.save
flash[:notice] = "Welcome, #{@user.username}!"
session[:user_id] = @user.id
redirect_accordingly(@user)
else
flash[:alert] = "Some of the info you provided needs tweaking."
render :new
end
现在最后要注意的是,用户可以编辑html并输入&#34; admin&#34;作为选项值并尝试注册为管理员。因此,您希望在create method中的users_controller中对此进行限制:
localhost
希望有道理!让我知道,如果这不起作用或某些事情没有意义。快乐的编码!