【问题标题】:PHP: Matching hashed password with user input not working [duplicate]PHP:将哈希密码与用户输入匹配不起作用[重复]
【发布时间】:2015-09-10 04:31:53
【问题描述】:

我是 PHP 新手,正在尝试检查用户(登录页面)提供的密码是否与存储在数据库中的散列密码匹配。 数据库中的密码通过$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT);(与我用于用户输入的方法相同)进行散列处理,并存储在VARCHAR(255) 列中。

我现在尝试使用 password_verify 将其与用户输入进行比较,但出现以下错误,这是由 else 部分引起的。

有人可以告诉我我在这里做错了什么吗? 我也尝试删除“== true”,但这也不起作用。

我的 PHP:

$email = $_POST["email"];
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 

$stmt = $conn->prepare("SELECT email, pw FROM Users WHERE email = ?");
$stmt->bind_param('s', $email);
$stmt->execute();
$result = $stmt->get_result();
if(mysqli_num_rows($result) == 0){
    echo "Email has not been registered yet";
}else{
    if(password_verify($pw, $result["pw"]) == true){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
};

错误:

"Fatal error: Cannot use object of type mysqli_result as array..."

更新:
对我来说,这与另一个被称为可能重复的问题不同,因为在我的情况下,我要么得到上述错误,要么(当遵循下面的 Bing 方法时)结果总是“密码不正确”——与输入无关。

提前非常感谢。

【问题讨论】:

  • print_r($result)转储你的结果,它是对象,可以通过$result->pw检索
  • $pw 包含用户输入密码的哈希值。因此,当您执行password_veryify() 时,实际上是根据数据库中的哈希值检查密码哈希值。您应该根据数据库中的哈希检查用户提供的原始密码。
  • PHP 错误的第一条规则:使用 Google 搜索错误消息。
  • @Jeemusu 该错误与password_hash()无关,与mysqli有关
  • 没错,流浪汉,但是一旦解决了你就会发现password_verify()确实存在问题。

标签: php mysql hash passwords


【解决方案1】:

您的代码存在两个问题。

第一个如错误消息中所述。您将结果作为对象返回,而不是数组。您应该将这些值作为对象访问:

$result->pw

第二个问题与您的 password_verify() 函数有关。 $pw 包含用户输入密码的哈希值。因此,当您执行password_veryify() 时,您实际上是根据数据库中的哈希值检查密码的哈希值。您应该根据数据库中的哈希检查用户提供的原始密码

【讨论】:

  • 也谢谢你。
【解决方案2】:

您的$result 变量包含mysqli_result 对象,不是您期望的数组。查看文档中的返回值部分,这里:http://php.net/manual/en/mysqli.query.php

要转换它,只需调用mysqli_fetch_array(它将mysqli_result 作为参数)并构建您的结果。您的代码如下所示:

$result_object = $stmt->get_result();
$result_array = array();
while($result_item = mysqli_fetch_array($result_object)) {
    array_push($result_array, $result_item);
}

if(count($result_array) == 0){
    echo "Email has not been registered yet";
}else{
    $single_entry = array_pop($result_array);
    if(isset($single_entry["pw"]) && password_verify($single_entry["pw"], $pw)){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
}

几个注意事项:

  1. 你不需要; 在你的最终} 的末尾
  2. 您将在$result_array 中获得一个二维数组,这就是我添加array_pop() 的原因,假设您只有一条电子邮件记录。
  3. password_verify() 调用中的参数顺序错误,您会注意到我切换了它们。
  4. 对此进行了测试,但它应该能让你顺利进行。

【讨论】:

  • 关于这个的最后一个问题:我什至需要“== true”吗?看起来他们在 php.net 上忽略了这个。
  • 很高兴为您提供帮助。注意注意#2。理解多维数组很重要。更多好读:w3schools.com/php/php_arrays_multi.asp
  • 是的,您可以在任何地方忽略== true。请注意,这是 两个 = 标志。三是不同的问题:stackoverflow.com/questions/80646
  • 不,在 PHP 中的任何地方都不需要 ;} 之后。 } 就像结束一个段落,然后添加 ; 就像一个额外的句号。 Switch 语句可能需要 break;确实; 结尾)在 case 之间(因此它们不会全部按顺序运行,从第一个匹配开始),但这是一个单独的操作。跨度>
【解决方案3】:

你实际上做错了两件事。

验证哈希 请注意,password_hash() 将算法、成本和盐作为返回哈希的一部分返回。因此,验证哈希所需的所有信息都包含在其中。这允许验证函数验证哈希,而无需单独存储盐或算法信息。 ..from php.net

从数据库中检索密码 mysqli_num_rows 函数不返回密码哈希。试试fetch这个专栏。

但是您使用的是 prepare 语句,因此您必须像 here 所示那样进行操作。所以你会做这样的事情:

//Remove
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 
$result = $stmt->get_result();

//Add
$stmt->bind_result($pw);
$stmt->fetch();

//Replace
if(mysqli_num_rows($result) == 0){
...
if(password_verify($pw, $result["pw"]) == true){
//With
if(empty($pw)){
...
if(password_verify($_POST["pw"], $pw) == true){

【讨论】:

  • 谢谢!你能解释一下我应该怎么做才能涵盖你答案的第二部分吗?
  • @TaneMahuta $conn 里面是什么你用的是mysqli还是pdo?根据您使用的内容,我可以给出更详细的答案。
  • 谢谢 - 我使用 mysqli: $conn = new mysqli($dbServer, $dbUser, $dbPass, $dbName); $conn->set_charset("utf8");
  • 只是在这里添加:这还没有解决。我正在尝试此处发布的另一种方法,但这并未检测到密码正确(尚未)。
  • @TaneMahuta 更新了我的答案检查这是否适合你。
【解决方案4】:

到目前为止,我浏览了所有提供的答案,但要么无法让它们充分发挥作用,要么无法让它们向我返回正确的结果。

由于我是 PHP 新手,这可能是由于我对提供的 cmets 的某些部分缺乏了解,对此我深表歉意,但我找到了适合我的解决方案。

我确信这不是一个完美的方法,我很高兴根据收到的反馈和建议进一步改进它 - 一开始,运行某些东西对我来说很重要,因为我需要处理依赖于此的其他部分。

这是我目前的(工作)解决方案:

$email = $_POST["email"];
$pw = $_POST["pw"]; 

$stmt = $conn->prepare("SELECT email FROM Users WHERE email = ?");
$stmt->bind_param('s', $email);
$stmt->execute();
$result = $stmt->get_result();
if(mysqli_num_rows($result) == 0){
    echo "Email has not been registered yet";
}else{
    $stmt = $conn->prepare("SELECT pw FROM Users WHERE email = ? LIMIT 1");
    $stmt->bind_param('s', $email);
    $stmt->execute();
    $result = $stmt->get_result();
    $pwHashed = $result->fetch_assoc();
    if(password_verify($pw, $pwHashed["pw"])){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 2016-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多