【问题标题】:Storing a password in a web database?将密码存储在 Web 数据库中?
【发布时间】:2016-01-15 09:21:16
【问题描述】:

所以,我想要达到的目标如下: 当您进入网站时,只有一个密码框。如果您输入与数据库中的密码匹配的密码,则会打开一个包含更多信息的弹出窗口。我该怎么做呢?

【问题讨论】:

  • 您使用的是什么网络服务器/应用程序?

标签: database passwords


【解决方案1】:

让我们分解你的问题:

  • 您需要一个允许用户登录的索引页面
  • 要允许用户登录,您需要使用联系某种登录功能的表单(最简单的方法)或 AJAX 请求(稍微困难的方法)。 (我将在我的示例中使用 PHP,但您可以根据需要使用其他语言。)
  • 在 PHP 脚本中,您需要能够访问数据库。 (MySQLiPDO 是目前推荐的 PHP 类。)
  • 连接到数据库后,您需要查询数据库以从表中获取相关行。
  • 现在您需要从行中获取数据并执行必要的检查。
  • 最后,您需要向浏览器返回一些数据,以便浏览器知道下一步该做什么。 (确保您的代码能够回答以下问题:登录是否成功?应该打开什么弹出窗口?应该显示什么错误消息?应该设置什么 cookie?等等)。

网站登录比这更多,但这只是您问题的一般细分。

以下是我将在示例中为您使用的内容: - 我将 PHP 用于动态服务器端脚本 - 我将为 AJAX 登录请求使用一些 JavaScript(只是 vanilla JS,而不是 jQuery 或其他变体)。 显然你可以在你的实现中随意使用其他东西。

我将首先创建index.html,如下所示:

<!DOCTYPE html>
<html lang="en"> <!-- Assuming the language is English -->
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Some Snazzy Title for Login Page</title>
        <script type="text/javascript" src="resources/js/functions.js"></script>
        <!-- Any additional things you want to include in the head of the HTML page -->
    </head>
    <body>
        <!-- Table is used here for formatting -->
        <table id="LoginTable" style="margin-left:auto;margin-right:auto;">
            <tr>
                <td>Username:</td>
                <td><input type="text" name="username" id="username"></td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type="password" name="password" id="password"></td>
            </tr>
        </table>
        <br>
        <!--- Button to call our JavaScript AJAX login function: -->
        <button onclick="AttemptLogin();">Login</button>
        <!--- Include links to things like register, forgot password, and etc. here -->
    </body>
</html>

您会注意到,我们包含一个名为 functions.js 的外部 JavaScript 文件,该文件位于 resources/js/ 子目录中。因此,要包含此内容,您将在与 index.html 相同的目录中创建一个名为 resources 的文件夹,然后在 内创建一个名为 js 的文件夹资源 文件夹。完成之后,我们就可以创建functions.js了:

/* Credits to Minko Gechev (blog.mgechev.com) for createXMLHttp() (I have made my own modifications to it, though.) */
function createXMLHttp(){
        //If XMLHttpRequest is available then using it
    if (typeof XMLHttpRequest !== undefined) {
        // XMLHttpRequest is a fairly standard class in most browsers for handling AJAX, but
        // it's not defined in all browsers (including IE)
        return new XMLHttpRequest;
    } else if (window.ActiveXObject) {
        // User is using Internet Explorer
        // Now we'll try to use an array of various IE XML HTTP types to find the right one:
        var ieXMLHttpVersions = ['Microsoft.XMLHTTP', 'MSXML2.XMLHttp.5.0', 'MSXML2.XMLHttp.4.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp', 'Microsoft.XMLHttp'];
        var xmlHttp;

        // Look through the array and try to create the XMLHttp object
        for (var i = 0; i < ieXMLHttpVersions.length; i++) {
            try {
                xmlHttp = new ActiveXObject(ieXMLHttpVersions[i]);
                return xmlHttp;
            } catch (e) {
                // Do nothing with error
            }
        }

        // Despite the fact that ActiveXObject is defined, none of the XMLHttp versions could be
        // successfully created. The browser's JavaScript implementation is unknown and thus we cannot
        // use AJAX for this.
        return null;
    }else{
        // This browser is unknown and it does not support any of the common XML HTTP classes.
        // As such, we will not be able to AJAX for login through this.
        return null;
    }
}

function AttemptLogin(){
    // First we'll get the current timestamp which we'll append to the login link to prevent caching:
    var timestamp = new Date().getTime();
    // Link to POST login data to (with cache-buster):
    var url = "ajax/login_process.php?cachebuster=" + timestamp;
    var username = encodeURIComponent(document.getElementById("username").value);
    var password = encodeURIComponent(document.getElementById("password").value);

    var PostRequestData = "u=" + username + "&p=" password";

    var xmlHttp = createXMLHttp();

    if(xmlHttp === null){
        // xmlHttp could not be successfully created
        // Alert the user of this issue and recommend a browser upgrade
        alert("An error occurred that prevented us from logging in.\nThis issue seems to have been caused by your browsers JavaScript implementation. Please consider updating your browser to the newest version or installing a different browser.");
        // Exit the function prematurely
        return;
    } // Else, xmlHttp appears to have been created successfully

    xmlHttp.open('POST', url, true);
    xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    // Code the callback function which will be executed after the request completes.
    xmlHttp.onreadystatechange = function(){
        if( xmlHttp.readyState == 4 && xmlHttp.status == 200 ){
            // It seems like the request successfully executed
            // Now we'll just need to check if the login was successful or not:
            var respText = xmlHttp.responseText;

            if(respText.indexOf("login success") > -1){
                // Now we'll open a popup window here:
                window.open('info.phtml', 'More Information', 'height=400,width=400');
                // Info.phtml will do additional security checks before displaying the information, by the way.
            }else{
                alert("Error: either the username does not exist or the is incorrect for the username provided.\nPlease try again.");
            }
        }
    }

    // Now that we have the request open, the request header is set, and the callback
    // function is defined, we will finally send the actual login request to the login_process.php page:
    xmlHttp.send(PostRequestData);
}

现在我们需要写出login_process.php 的代码。不过,在此之前,我们需要创建此文件的目录。因此,在您放置index.html 文件的同一个文件夹中,您应该创建一个名为ajax 的子目录。现在我们将写入该文件夹中的login_process.php 文件:

<?php
    // Start up a session so we can hold whether the user is logged in or not:
    session_start();

    // To further prevent caching we'll use these headers:
    header("Cache-control: no-store, no-cache, must-revalidate");
    header("Expires: " . gmdate("D, d M Y H:i:s", (time() + 2)) . " GMT");
    header("Date: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Pragma: no-cache");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");

    // Make sure the request is valid:
    if($_SERVER['REQUEST_METHOD'] != 'POST'){
        die("Invalid request type");
    }

    // Now let's do the login.
    // First, connect to the database:
    $mysqli = new mysqli("Your database host", "Your database username", "Your database password", "The database name");

    if($mysqli->connect_errno){
        die("Failed to connect to database");
    }

    // Next we'll get the request parameters
    $username = $_POST['u'];
    $password = $_POST['p'];

    // Now we need to clean the username so we can search the database for it
    $safeUsername = $mysqli->real_escape_string($username); // Prevents SQL injection

    // Next let's query to see if this username exists:
    $result = $mysqli->query("SELECT * FROM `TableName` WHERE `username`='$safeUsername' LIMIT 1;");

    if($result->num_rows == 0){
        // The username is unknown.
        // Close the database members and die with vague error message
        $result->free();
        $mysqli->close();
        die("fail");
    } // Else, username exists

    // Get this user's salts and password hash:
    $row = $result->fetch_assoc();

    // Now that we have the results as a PHP keyed array, we do not need to keep
    // the database open any longer. So we will now close the database connection and
    // free the database-related objects from the memory.
    $result->free();
    $mysqli->close();

    // Now pull out the database provided values to local variables (for convenience):
    $passwordSalt_1 = $row['salt1'];
    $passwordSalt_2 = $row['salt2'];
    $passwordHash = strtolower($row['passHash']); // Hexdigest of users current password hash

    // Hash the users password with the salt and see if the results match:
    $userPasswordData = $passwordSalt_1 . $password . $passwordSalt_2;
    $requestedPassHash = strtolower(hash('sha512', $userPasswordData));

    // Now we just need to see if the user's passHash in the database is the same as
    // the hash we just generated via the password sent in the request:
    $isLoggedIn = ($passwordHash == $requestedPassHash);

    $_SESSION['logged_in'] = ($isLoggedIn ? '1' : '0');

    // Send back the login result to the AJAX callback function:
    die(($isLoggedIn ? "login success" : 'fail'));
?>

现在我们剩下的就是编码info.phtml(弹出网页):

<?php
    // Start up the session so we can access the session variables:
    session_start();

    // We certainly don't want the browser to cache our webpage which should require login:
    header("Cache-control: no-store, no-cache, must-revalidate");
    header("Expires: " . gmdate("D, d M Y H:i:s", (time() + 2)) . " GMT");
    header("Date: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Pragma: no-cache");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");

    // Now we'll simply check if the user is logged in by referencing the session:
    if( !isset($_SESSION['logged_in']) || // Check if session variable is set
        empty($_SESSION['logged_in']) || // Check if the variable isn't empty
        ($_SESSION['logged_in'] != '1') ){ // Check if the variable is anything other than the valid value

        // If any of the above statements are true, we reach this code and the user is not properly logged in
        // As such, we should display an error page message instead of displaying the page.
        header($_SERVER["SERVER_PROTOCOL"] . " 418 I'm a teapot", true, 418);
        /* Personal Note: I'm using 418 'I'm a teapot' here out of personal preference.
           Technically the RFC has not defined a response code for telling a user that they need
           to login to the website before accessing the page, but sending back a non-4xx response
           does not seem reasonable. 4xx response codes tell the client that there was an error
           with their request. Since this wasn't a server a error and the request did not go over
           successfully, a level 4xx response is the most fitting. */

        die("Error: You need to login before accessing this page.");
    } // Else, the user is logged in. Go ahead and show them the page.
?>

希望这可以帮助您设置您的网站。如果这确实有帮助,请不要忘记投票。 (不是试图乞求,但我确实花了很长时间写下你的问题的答案:P)我没有测试提供的代码,所以我确信整个过程中可能存在一些小错误。显然,您需要重写代码的某些部分以适应您的情况,但总的来说,它应该让您深入了解这种可以编码的系统。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2012-09-25
    • 2011-02-27
    • 1970-01-01
    • 2020-03-20
    • 2016-12-25
    • 2011-07-15
    相关资源
    最近更新 更多