更改用户表中的列时出现身份验证问题
我对 Rails 很陌生,我正在尝试解决以下身份验证问题:
用户发表评论或授予“赦免”(类似于评论),他会为此获得一些硬币。硬币是我的应用程序中的虚拟货币,也是用户表中的一列。
由于您的善意帮助,我已经能够在撰写评论或授予赦免后更新硬币价值。但是,当我写评论并退出后,我的登录名或密码就会更改(?)...我无法再使用此帐户登录。
这就是我的用户模型的样子:
require 'digest'
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation, :twitter_url, :homepage_url, :coins
has_many :comments, :dependent => :destroy
has_many :absolutions, :dependent => :destroy
has_many :ratings
has_many :rated_sins, :through => :ratings, :source => :sins
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
homepage_regex = /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :twitter_url, :format => { :with => homepage_regex }
validates :homepage_url, :format => { :with => homepage_regex }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
class << self
def authenticate(email, submitted_password)
user = find_by_email(email)
(user && user.has_password?(submitted_password)) ? user : nil
end
def authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
end
private
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
这是我的评论控制器:
class CommentsController < ApplicationController
before_filter :authenticate, :only => [:create, :destroy]
def new
@comment = Comment.new
end
def create
@sin = Sin.find(params[:sin_id])
@comment = current_user.comments.build(params[:comment])
@comment.sin_id = @sin.id
if @comment.save
flash[:success] = "Comment created! Earned 20 coins."
coins_new = current_user.coins.to_i + 20
current_user.update_attribute(:coins, coins_new)
redirect_to sin_path(@sin)
else
flash[:error] = "Comment should have 1 - 1000 chars."
redirect_to sin_path(@sin)
end
end
def destroy
end
private
def authenticate
deny_access unless signed_in?
end
end
我认为它与 before_save encrypt_password 方法有关,但这只是一个猜测。我非常感谢您的帮助和建议!
编辑: 天气变暖了......这与评论控制器中的以下行有关:
current_user.update_attribute(:coins, coins_new)
当他更新:硬币列时,似乎出了问题。如果您需要更多信息,请发表评论。感谢您的帮助!
I'm very new to rails and I'm trying to accomplish the following authentication issue:
User makes a comment or grants "absolution" (similar to comment) and he gets some coins for it. Coins is the virtual currency in my app and is also a column in the users table.
Because of your kind help, I was already capable to update the coins value after writing a comment or grant absolution. However, when I write a comment and log out after that, my login name or password gets changed(?)...I can't login anymore with this account.
This is how my User model looks like:
require 'digest'
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation, :twitter_url, :homepage_url, :coins
has_many :comments, :dependent => :destroy
has_many :absolutions, :dependent => :destroy
has_many :ratings
has_many :rated_sins, :through => :ratings, :source => :sins
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
homepage_regex = /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :twitter_url, :format => { :with => homepage_regex }
validates :homepage_url, :format => { :with => homepage_regex }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
class << self
def authenticate(email, submitted_password)
user = find_by_email(email)
(user && user.has_password?(submitted_password)) ? user : nil
end
def authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
end
private
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
And this is my comments controller:
class CommentsController < ApplicationController
before_filter :authenticate, :only => [:create, :destroy]
def new
@comment = Comment.new
end
def create
@sin = Sin.find(params[:sin_id])
@comment = current_user.comments.build(params[:comment])
@comment.sin_id = @sin.id
if @comment.save
flash[:success] = "Comment created! Earned 20 coins."
coins_new = current_user.coins.to_i + 20
current_user.update_attribute(:coins, coins_new)
redirect_to sin_path(@sin)
else
flash[:error] = "Comment should have 1 - 1000 chars."
redirect_to sin_path(@sin)
end
end
def destroy
end
private
def authenticate
deny_access unless signed_in?
end
end
I assume, that it has something to do with the before_save encrypt_password method, but its only a guess. I really appreciate your help and suggestions!
Edit:
It gets warmer...It has something to do with the following line in the Comments Controller:
current_user.update_attribute(:coins, coins_new)
When he updates the :coins column, something seems to go wrong. If you need further info, just drop a comment. Thanks for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的问题是您正在“加密密码”方法中加密已经加密的密码。
因此,当用户是
new_record?
时,您将获取密码(假设它是“cat”),对其进行哈希处理,然后将其存储在数据库中。因此,存储的是“cat”的加密哈希,我们称之为“dog”
然后,下次保存用户记录时,您将采用哈希密码(“dog”) #2 你的“加密密码”方法,并再次散列,我们会说生成“袋鼠”。
下次登录时,您的应用程序将对您在登录表单“cat”中输入的密码进行哈希处理,将其哈希为“dog”,并将其与数据库中的哈希版本“kangaroo”进行比较。哦,但是“dog”与“kangaroo”不匹配,所以登录失败。
因此更改:
为:
或:
Your problem is that you're encrypting the already encrypted password in your "encrypt_password" method.
So, when the user is a
new_record?
, you're taking the password (say it's "cat"), hashing it, and storing it in the database.So, what gets stored is a cryptographic hash of "cat", which we'll say is "dog"
Then, the next time you're saving the user record, you're taking the hashed password ("dog") in line #2 of your "encrypt_password" method, and hashing it again, which we'll say generates "kangaroo".
Next time you log in, your app is hashing the password you enter into the login form "cat", hashing it to "dog", and comparing it to the hashed version in the database, "kangaroo". Oh, but "dog" doesn't match "kangaroo", so the login fails.
So change:
To either:
Or: