如何保存密码散列以便匹配已经散列的密码?
How do I save a password hash so I can match an already hashed password?
我正在实施一项 "remember me" 功能 (CakePHP 3),该功能在 cookie 中存储用户名和散列密码。我的问题是我无法成功地将 cookie 中的散列密码与数据库中的散列密码进行匹配。
我正在使用 DefaultPasswordHasher 生成数据库哈希和 cookie 哈希。我最初认为这些会匹配,但事实并非如此。
我的第二个想法是 DefaultPasswordHasher 有一个函数可以验证两个哈希值是否来自同一个密码,但它的 check() 函数需要一个纯文本密码:https://api.cakephp.org/3.3/class-Cake.Auth.DefaultPasswordHasher.html
网上类似的问题似乎都适用于旧版本的 Cake 或者没有定论。
来自用户实体:
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
来自 UsersController login() 函数
// Remember login?
if ($this->request->getData()['remember_me'] == "true") {
// Hash the user's password
$savedUser = [
'password' => (new DefaultPasswordHasher)->hash($this->request->getData()['password']),
'username' => $this->request->getData()['username']
];
// Save login for 1 month
$result = $this->Cookie->write('cookie_name', $savedUser, true, '1 month');
}
来自 AppController initialize() 函数:
// Load logged in user
$loggedInUserID = $this->Auth->user('id');
// If not logged in try cookie
if( !$loggedInUserID && $cookie = $this->Cookie->read('cookie_name') ) {
error_log("Attempting to log in from cookie. Username: ".$cookie['username']);
$user = $this->Users->find('all', [
'conditions' => [
'username' => $cookie['username'],
'password' => $cookie['password'],
'is_deleted' => 0
]
])
->first();
// If a user was found, try to login
if ($user) {
if($this->Auth->login($user)) {
error_log("Successfully logged in from cookie. Username: ".$cookie['username']);
$loggedInUserID = $this->Auth->user('id');
} else {
error_log("Couldn't log in from cookie. Username: ".$cookie['username']);
$this->redirect('/users/logout'); // destroy session & cookie
}
}
}
(为了清楚起见,我保留了临时错误日志消息。)
cookie 似乎保存正确,但其哈希值与数据库不匹配,这意味着从未找到与 cookie 匹配的用户。
问题是两个哈希应该匹配吗?或者我应该使用一个函数来匹配两个哈希值吗?
首先,您可能想看看新的身份验证插件,它随附开箱即用的 cookie 身份验证器!
https://book.cakephp.org/authentication/1.1/en/
也就是说,你的前提是错误的,两个哈希不匹配的事实是设计使然,并且是正确的行为,没有可以匹配它们的方法。
您应该做的是在您的 cookie 中存储一个唯一标识符,比方说用户名,以及从第二个凭据构建的散列,您需要在尝试登录时再次构建的散列通过 cookie 数据。比方说用户名的哈希值 + 哈希密码,hashed 密码,因为您需要再次使用该精确值来重新创建普通值,以便将其与存储在cookie,即您不能(也不应该)使用普通密码,因为它在后续请求中不再可用。
然后在使用cookie数据登录时,使用唯一标识符(用户名)查询用户,通过密码哈希器check()
方法。
你给的例子看起来像这样(免责声明,这是未经测试的示例代码):
$user = $this->Users->get($this->Auth->user('id'));
$savedUser = [
'username' => $user->username,
'token' => (new DefaultPasswordHasher())->hash(
$user->username . ':' . $user->password
),
];
// ...
查询并使用当前登录的用户,因此您必须在调用 $this->Auth->identify()
!
之后执行此操作
// ...
$user = $this->Users
->find()
->where([
'username' => $cookie['username'],
'is_deleted' => 0,
])
->first();
if ($user) {
$plain = $user->username . ':' . $user->password;
if ((new DefaultPasswordHasher())->check($plain, $cookie['token'])) {
// the hash matches, log the user in
$user = $user->toArray();
unset($user['password']); // but do not put the password in the session
$this->Auth->setUser($user);
} else {
// the hash doesn't match, do something else
}
}
注意setUser()
的使用,CakePHP中没有login()
方法3.xAuthComponent
,login()
方法来自CakePHP2.x!同样理想情况下,您将在自定义身份验证对象和 Auth.afterIdentify
事件的事件处理程序中处理所有这些,并将逻辑置于控制器之外。
另见
我正在实施一项 "remember me" 功能 (CakePHP 3),该功能在 cookie 中存储用户名和散列密码。我的问题是我无法成功地将 cookie 中的散列密码与数据库中的散列密码进行匹配。
我正在使用 DefaultPasswordHasher 生成数据库哈希和 cookie 哈希。我最初认为这些会匹配,但事实并非如此。
我的第二个想法是 DefaultPasswordHasher 有一个函数可以验证两个哈希值是否来自同一个密码,但它的 check() 函数需要一个纯文本密码:https://api.cakephp.org/3.3/class-Cake.Auth.DefaultPasswordHasher.html
网上类似的问题似乎都适用于旧版本的 Cake 或者没有定论。
来自用户实体:
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
来自 UsersController login() 函数
// Remember login?
if ($this->request->getData()['remember_me'] == "true") {
// Hash the user's password
$savedUser = [
'password' => (new DefaultPasswordHasher)->hash($this->request->getData()['password']),
'username' => $this->request->getData()['username']
];
// Save login for 1 month
$result = $this->Cookie->write('cookie_name', $savedUser, true, '1 month');
}
来自 AppController initialize() 函数:
// Load logged in user
$loggedInUserID = $this->Auth->user('id');
// If not logged in try cookie
if( !$loggedInUserID && $cookie = $this->Cookie->read('cookie_name') ) {
error_log("Attempting to log in from cookie. Username: ".$cookie['username']);
$user = $this->Users->find('all', [
'conditions' => [
'username' => $cookie['username'],
'password' => $cookie['password'],
'is_deleted' => 0
]
])
->first();
// If a user was found, try to login
if ($user) {
if($this->Auth->login($user)) {
error_log("Successfully logged in from cookie. Username: ".$cookie['username']);
$loggedInUserID = $this->Auth->user('id');
} else {
error_log("Couldn't log in from cookie. Username: ".$cookie['username']);
$this->redirect('/users/logout'); // destroy session & cookie
}
}
}
(为了清楚起见,我保留了临时错误日志消息。)
cookie 似乎保存正确,但其哈希值与数据库不匹配,这意味着从未找到与 cookie 匹配的用户。
问题是两个哈希应该匹配吗?或者我应该使用一个函数来匹配两个哈希值吗?
首先,您可能想看看新的身份验证插件,它随附开箱即用的 cookie 身份验证器!
https://book.cakephp.org/authentication/1.1/en/
也就是说,你的前提是错误的,两个哈希不匹配的事实是设计使然,并且是正确的行为,没有可以匹配它们的方法。
您应该做的是在您的 cookie 中存储一个唯一标识符,比方说用户名,以及从第二个凭据构建的散列,您需要在尝试登录时再次构建的散列通过 cookie 数据。比方说用户名的哈希值 + 哈希密码,hashed 密码,因为您需要再次使用该精确值来重新创建普通值,以便将其与存储在cookie,即您不能(也不应该)使用普通密码,因为它在后续请求中不再可用。
然后在使用cookie数据登录时,使用唯一标识符(用户名)查询用户,通过密码哈希器check()
方法。
你给的例子看起来像这样(免责声明,这是未经测试的示例代码):
$user = $this->Users->get($this->Auth->user('id'));
$savedUser = [
'username' => $user->username,
'token' => (new DefaultPasswordHasher())->hash(
$user->username . ':' . $user->password
),
];
// ...
查询并使用当前登录的用户,因此您必须在调用 $this->Auth->identify()
!
// ...
$user = $this->Users
->find()
->where([
'username' => $cookie['username'],
'is_deleted' => 0,
])
->first();
if ($user) {
$plain = $user->username . ':' . $user->password;
if ((new DefaultPasswordHasher())->check($plain, $cookie['token'])) {
// the hash matches, log the user in
$user = $user->toArray();
unset($user['password']); // but do not put the password in the session
$this->Auth->setUser($user);
} else {
// the hash doesn't match, do something else
}
}
注意setUser()
的使用,CakePHP中没有login()
方法3.xAuthComponent
,login()
方法来自CakePHP2.x!同样理想情况下,您将在自定义身份验证对象和 Auth.afterIdentify
事件的事件处理程序中处理所有这些,并将逻辑置于控制器之外。
另见