PHP basic digest API接口鑒權(quán)

關(guān)于basic認(rèn)證和digest認(rèn)證的初步理解

初代的是basic的認(rèn)證,比較容易被破解。升級(jí)版的就是加上摘要basic digest。可用于api接口請(qǐng)求的一個(gè)過(guò)濾,為api的安全提供一定的保護(hù)

需要注意的地方

有個(gè)問(wèn)題是前端ajax會(huì)發(fā)送一個(gè)預(yù)請(qǐng)求OPTION,后端需要對(duì)此作出正確的回應(yīng)前端ajax才會(huì)真正的請(qǐng)求。

if($_SERVER['REQUEST_METHOD']=='OPTION'){
header('HTTP/1.1 200');
}

后端代碼

        if($_SERVER['REQUEST_METHOD']=='OPTION'){
            header('HTTP/1.1 200');
        }//需要正確的回應(yīng)前端預(yù)請(qǐng)求,否則前端不會(huì)發(fā)出真正的請(qǐng)求
        $realm = 'abc';            //密鑰
        $username = 'add';          //帳號(hào)
        $passowrd = '123123';       //密碼
        $exit_user= $this->dao->select('*')->from('api_user')->where('restid')->eq($username)->andWhere('status')->eq(1)->fetch();//查找這個(gè)用戶,判斷是否存在和是否啟用
        if (!$exit_user) {//不存在該賬號(hào)
            Response::error('', 'fail');
        }
        $realm = $exit_user->realm;
        $passowrd = $exit_user->restkey;
        if (empty($_SERVER['PHP_AUTH_DIGEST']) && false) {//判斷頭部信息是否有添加
            header('HTTP/1.1 401 Unauthorization Required');    //401 此頭彈出登錄窗口
            header('WWW-Authenticate: Digest realm="' . $realm . '",qop="auth", nonce="' . uniqid() . '", opaque="' . md5($realm) . '"');
            die('您取消了本次登錄,若重新登錄,請(qǐng)刷新此頁(yè)面。');
        } else {

            //使用函數(shù)http_digest_parse解析驗(yàn)證信息
            if (!($data = $this->http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || $data['username'] != $username) {
//                var_dump($data);
                header("HTTP/1.1 401 Unauthorization Required");
                header('WWW-Authenticate: Digest realm="'.$realm.'",qop="auth", nonce="'.uniqid().'", opaque="'.md5($realm).'"');//IE 8 需要重新發(fā)送,不然不彈窗
                die('賬號(hào)不一致錯(cuò)誤!');
            }

            //拼接字符串
            $A1 = md5($username . ':' . $realm . ':' . $passowrd);
            $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
            $valid_response = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);

            if ($data['response'] != $valid_response) {
                header("HTTP/1.1 401 Unauthorization Required");
                header('WWW-Authenticate: Digest realm="' . $realm . '",qop="auth", nonce="' . uniqid() . '", opaque="' . md5($realm) . '"');
                die('賬號(hào)/密碼錯(cuò)誤!加密后的字符串和前端提交上來(lái)的不一樣,肯定有某個(gè)地方兩端沒(méi)有統(tǒng)一');
            }

            echo 'Hi ' . $username . ',恭喜你登錄成功!';
        }




// 解析字符串方法
    function http_digest_parse($txt)
    {
        $needed_parts = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1);
        $data = array();

        preg_match_all('@(\w+)=([\'"]?)([a-zA-Z0-9=./\_-]+)\2@', $txt, $matches, PREG_SET_ORDER);
        foreach ($matches as $m) {
            $data[$m[1]] = $m[3];
            $data['uri'] = $_SERVER['REQUEST_URI'];
            unset($needed_parts[$m[1]]);
        }
        return $data;
    }

前端代碼

//basic digest 的頭部摘要   type需要對(duì)應(yīng)當(dāng)前提交的類(lèi)型 , POST ,PUT , DELETE , GET
function ajax(type,data={}) {
let url = 'http://your_uri/'
let path = 'api/index.php?m=web&f=authSql'   //你的請(qǐng)求地址

let bodyurl = "/api/index.php?m=web&f=authSql";
var userstr = encrypt('yourusername', 'yourpassword', bodyurl, type,'yourrealm');   //  yourname 和yourpassword,yourrealm是需要和后端統(tǒng)一才行。后端用一個(gè)表專(zhuān)門(mén)存這些數(shù)據(jù)
return new Promise((resolve) =>{
$.ajax({
method: type,
url: `${url}${path}`,
data:data,
dataType :'json',
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization",userstr);  //把加密后的字符串添加到頭部信息中
},
success:(res) =>{
resolve(res)
}
});
})

}



//加密形成摘要的規(guī)則也需要和前端統(tǒng)一
function encrypt( userName, password,requestBody,method,yourrealm) {

    var usermd = hex_md5(userName + ":'"+yourrealm+"':" + password);

    var rqmd = hex_md5(method+":"+requestBody);
    var mainmd = hex_md5(usermd+":1:1:1:auth:"+rqmd);
    var head ='Digest username="'+userName+'", realm="'+yourrealm+'", nonce="1", uri="'+requestBody+'", qop=auth, nc=1, cnonce="1", response="'+mainmd+'", opaque="1"'
    return head;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容