PHP 模擬 HTTP 摘要認證(Digest )


 

<?php

header("Content-type: text/html; charset=utf-8");

/*php摘要認證*/

$users = ['dee'=>'123456', 'admin'=>'admin'];
$realm = 'My Website';
$username = validate_digest($realm, $users);

print 'Hello, '.htmlentities($username);

function validate_digest($realm, $users) {

    if(! isset($_SERVER['PHP_AUTH_DIGEST'])) {
        send_digest($realm);
    }

    //如果摘要無法解析,則會失敗
    //var_dump($_SERVER['PHP_AUTH_DIGEST']);
    //string 'username="你輸入的用戶名", realm="My Website", nonce="403b875881c55e60a6addd42b904a19c", uri="/php/phpcookbook/web/digest.php", response="080da94742f55682242e9c024529c298", opaque="49918e38b4734f44ffa587368a9e3e1a", qop=auth, nc=00000001, cnonce="d48ffb5a6cd062fc"' (length=253)
    $username = parse_digest($_SERVER['PHP_AUTH_DIGEST'], $realm, $users);
    if($username === false) {
        send_digest($realm);
    }
    return $username;
}

function send_digest($realm) {
    http_response_code(401);
    // header('HTTP/1.1 Unauthorized');
    $nonce = md5(uniqid()); //隨機數
    $opaque = md5($realm);
    header('WWW-Authenticate:Digest realm="'.$realm.'", qop="auth", nonce="'.$nonce.'", opaque="'.$opaque.'"');
    //響應頭 WWW-Authenticate:Digest realm="My Website", qop="auth", nonce="e0e5319efa00f94b815dbb4b34f88bb0", opaque="49918e38b4734f44ffa587368a9e3e1a"
    echo '需要用戶名和密碼才能繼續訪問';
    exit;
}

function parse_digest($digest, $realm, $users) {

    $digest_info = array();

    foreach(array('username', 'uri', 'nonce', 'cnonce', 'response') as $part) {
        if(preg_match('/'.$part.'=([\'"]?)(.*?)\1/', $digest, $match)) {
            $digest_info[$part] = $match[2];
        } else {
            return false;
        }
    }
    
    //確保提供了正確的qop
    if(preg_match('/qop=auth(,|$)/', $digest)) {
        $digest_info['qop'] = 'auth';
    } else {
        return false;
    }

    //確保提供了合法的nonce數
    if(preg_match('/nc=([0-9a-f]{8})(,|$)/', $digest, $match)) {
        $digest_info['nc'] = $match[1];
    } else{
        return false;
    }

    $A1 = $digest_info['username'].':'.$realm.':'.$users[$digest_info['username']];
    //var_dump($A1);
    //string '你輸入的用戶名:My Website:' (length=15)
    $A2 = $_SERVER['REQUEST_METHOD'].':'.$digest_info['uri'];
    //var_dump($A2);
    //string 'GET:/php/phpcookbook/web/digest.php' (length=35)
    $request_digest = md5(implode(':', [
            md5($A1),
            $digest_info['nonce'],
            $digest_info['nc'],
            $digest_info['cnonce'],
            $digest_info['qop'],
            md5($A2)
        ]));

    //比較發送的摘要與我們計算的摘要是否一致
    if($request_digest != $digest_info['response']) {
        return false;
    }

    //一切正常,返回用戶名
    return $digest_info['username'];
}

 

參考:http協議之digest(摘要)認證

<PHP Cookbook,3rd>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM