Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
08dde0f3
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
08dde0f3
编写于
6月 28, 2018
作者:
R
Rafael Mendonça França
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #26764 from choncou/improve_has_secure_password
Allow configurable attribute name on `#has_secure_password`
上级
235809f6
9b63bf1d
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
72 addition
and
56 deletion
+72
-56
activemodel/CHANGELOG.md
activemodel/CHANGELOG.md
+18
-0
activemodel/lib/active_model/secure_password.rb
activemodel/lib/active_model/secure_password.rb
+48
-55
activemodel/test/cases/secure_password_test.rb
activemodel/test/cases/secure_password_test.rb
+4
-0
activemodel/test/models/user.rb
activemodel/test/models/user.rb
+2
-1
未找到文件。
activemodel/CHANGELOG.md
浏览文件 @
08dde0f3
*
Allows configurable attribute name for
`#has_secure_password`
. This
still defaults to an attribute named 'password', causing no breaking
change. There is a new method
`#authenticate_XXX`
where XXX is the
configured attribute name, making the existing
`#authenticate`
now an
alias for this when the attribute is the default 'password'.
Example:
class User < ActiveRecord::Base
has_secure_password :activation_token, validations: false
end
user = User.new()
user.activation_token = "a_new_token"
user.activation_token_digest # => "$2a$10$0Budk0Fi/k2CDm2PEwa3Be..."
user.authenticate_activation_token('a_new_token') # => user
*Unathi Chonco*
*
Add
`config.active_model.i18n_full_message`
in order to control whether
the
`full_message`
error format can be overridden at the attribute or model
level in the locale files. This is
`false`
by default.
...
...
activemodel/lib/active_model/secure_password.rb
浏览文件 @
08dde0f3
...
...
@@ -16,15 +16,16 @@ class << self
module
ClassMethods
# Adds methods to set and authenticate against a BCrypt password.
# This mechanism requires you to have a +password_digest+ attribute.
# This mechanism requires you to have a +XXX_digest+ attribute.
# Where +XXX+ is the attribute name of your desired password/token or defaults to +password+
#
# The following validations are added automatically:
# * Password must be present on creation
# * Password length should be less than or equal to 72 bytes
# * Confirmation of password (using a +
password
_confirmation+ attribute)
# * Confirmation of password (using a +
XXX
_confirmation+ attribute)
#
# If
password
confirmation validation is not needed, simply leave out the
# value for +
password
_confirmation+ (i.e. don't provide a form field for
# If confirmation validation is not needed, simply leave out the
# value for +
XXX
_confirmation+ (i.e. don't provide a form field for
# it). When this attribute has a +nil+ value, the validation will not be
# triggered.
#
...
...
@@ -37,9 +38,10 @@ module ClassMethods
#
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
#
# # Schema: User(name:string, password_digest:string)
# # Schema: User(name:string, password_digest:string
, activation_token_digest:string
)
# class User < ActiveRecord::Base
# has_secure_password
# has_secure_password :activation_token, validations: false
# end
#
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
...
...
@@ -48,11 +50,15 @@ module ClassMethods
# user.save # => false, confirmation doesn't match
# user.password_confirmation = 'mUc3m00RsqyRe'
# user.save # => true
# user.activation_token = "a_new_token"
# user.activation_token_digest # => "$2a$10$0Budk0Fi/k2CDm2PEwa3BeXO5tPOA85b6xazE9rp8nF2MIJlsUik."
# user.save # => true
# user.authenticate('notright') # => false
# user.authenticate('mUc3m00RsqyRe') # => user
# user.authenticate_activation_token('a_new_token') # => user
# User.find_by(name: 'david').try(:authenticate, 'notright') # => false
# User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
def
has_secure_password
(
options
=
{}
)
def
has_secure_password
(
attribute
=
:password
,
validations:
true
)
# Load bcrypt gem only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework)
# being dependent on a binary library.
...
...
@@ -63,9 +69,40 @@ def has_secure_password(options = {})
raise
end
include
InstanceMethodsOnActivation
attr_reader
attribute
define_method
(
"
#{
attribute
}
="
)
do
|
unencrypted_password
|
if
unencrypted_password
.
nil?
self
.
send
(
"
#{
attribute
}
_digest="
,
nil
)
elsif
!
unencrypted_password
.
empty?
instance_variable_set
(
"@
#{
attribute
}
"
,
unencrypted_password
)
cost
=
ActiveModel
::
SecurePassword
.
min_cost
?
BCrypt
::
Engine
::
MIN_COST
:
BCrypt
::
Engine
.
cost
self
.
send
(
"
#{
attribute
}
_digest="
,
BCrypt
::
Password
.
create
(
unencrypted_password
,
cost:
cost
))
end
end
define_method
(
"
#{
attribute
}
_confirmation="
)
do
|
unencrypted_password
|
instance_variable_set
(
"@
#{
attribute
}
_confirmation"
,
unencrypted_password
)
end
# Returns +self+ if the password is correct, otherwise +false+.
#
# class User < ActiveRecord::Base
# has_secure_password validations: false
# end
#
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
# user.save
# user.authenticate_password('notright') # => false
# user.authenticate_password('mUc3m00RsqyRe') # => user
define_method
(
"authenticate_
#{
attribute
}
"
)
do
|
unencrypted_password
|
attribute_digest
=
send
(
"
#{
attribute
}
_digest"
)
BCrypt
::
Password
.
new
(
attribute_digest
).
is_password?
(
unencrypted_password
)
&&
self
end
alias_method
:authenticate
,
:authenticate_password
if
attribute
==
:password
if
options
.
fetch
(
:validations
,
true
)
if
validations
include
ActiveModel
::
Validations
# This ensures the model has a password by checking whether the password_digest
...
...
@@ -73,57 +110,13 @@ def has_secure_password(options = {})
# when there is an error, the message is added to the password attribute instead
# so that the error message will make sense to the end-user.
validate
do
|
record
|
record
.
errors
.
add
(
:password
,
:blank
)
unless
record
.
password_digest
.
present?
record
.
errors
.
add
(
attribute
,
:blank
)
unless
record
.
send
(
"
#{
attribute
}
_digest"
)
.
present?
end
validates_length_of
:password
,
maximum:
ActiveModel
::
SecurePassword
::
MAX_PASSWORD_LENGTH_ALLOWED
validates_confirmation_of
:password
,
allow_blank:
true
validates_length_of
attribute
,
maximum:
ActiveModel
::
SecurePassword
::
MAX_PASSWORD_LENGTH_ALLOWED
validates_confirmation_of
attribute
,
allow_blank:
true
end
end
end
module
InstanceMethodsOnActivation
# Returns +self+ if the password is correct, otherwise +false+.
#
# class User < ActiveRecord::Base
# has_secure_password validations: false
# end
#
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
# user.save
# user.authenticate('notright') # => false
# user.authenticate('mUc3m00RsqyRe') # => user
def
authenticate
(
unencrypted_password
)
BCrypt
::
Password
.
new
(
password_digest
).
is_password?
(
unencrypted_password
)
&&
self
end
attr_reader
:password
# Encrypts the password into the +password_digest+ attribute, only if the
# new password is not empty.
#
# class User < ActiveRecord::Base
# has_secure_password validations: false
# end
#
# user = User.new
# user.password = nil
# user.password_digest # => nil
# user.password = 'mUc3m00RsqyRe'
# user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."
def
password
=
(
unencrypted_password
)
if
unencrypted_password
.
nil?
self
.
password_digest
=
nil
elsif
!
unencrypted_password
.
empty?
@password
=
unencrypted_password
cost
=
ActiveModel
::
SecurePassword
.
min_cost
?
BCrypt
::
Engine
::
MIN_COST
:
BCrypt
::
Engine
.
cost
self
.
password_digest
=
BCrypt
::
Password
.
create
(
unencrypted_password
,
cost:
cost
)
end
end
def
password_confirmation
=
(
unencrypted_password
)
@password_confirmation
=
unencrypted_password
end
end
end
end
activemodel/test/cases/secure_password_test.rb
浏览文件 @
08dde0f3
...
...
@@ -186,9 +186,13 @@ class SecurePasswordTest < ActiveModel::TestCase
test
"authenticate"
do
@user
.
password
=
"secret"
@user
.
activation_token
=
"new_token"
assert_not
@user
.
authenticate
(
"wrong"
)
assert
@user
.
authenticate
(
"secret"
)
assert
!
@user
.
authenticate_activation_token
(
"wrong"
)
assert
@user
.
authenticate_activation_token
(
"new_token"
)
end
test
"Password digest cost defaults to bcrypt default cost when min_cost is false"
do
...
...
activemodel/test/models/user.rb
浏览文件 @
08dde0f3
...
...
@@ -7,6 +7,7 @@ class User
define_model_callbacks
:create
has_secure_password
has_secure_password
:activation_token
,
validations:
false
attr_accessor
:password_digest
attr_accessor
:password_digest
,
:activation_token_digest
end
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录