PHP basic digest API接口鉴权

关于basic认证和digest认证的初步理解

初代的是basic的认证,比较容易被破解。升级版的就是加上摘要basic digest。可用于api接口请求的一个过滤,为api的安全提供一定的保护

需要注意的地方

有个问题是前端ajax会发送一个预请求OPTION,后端需要对此作出正确的回应前端ajax才会真正的请求。

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

后端代码

        if($_SERVER['REQUEST_METHOD']=='OPTION'){
            header('HTTP/1.1 200');
        }//需要正确的回应前端预请求,否则前端不会发出真正的请求
        $realm = 'abc';            //密钥
        $username = 'add';          //帐号
        $passowrd = '123123';       //密码
        $exit_user= $this->dao->select('*')->from('api_user')->where('restid')->eq($username)->andWhere('status')->eq(1)->fetch();//查找这个用户,判断是否存在和是否启用
        if (!$exit_user) {//不存在该账号
            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('您取消了本次登录,若重新登录,请刷新此页面。');
        } else {

            //使用函数http_digest_parse解析验证信息
            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 需要重新发送,不然不弹窗
                die('账号不一致错误!');
            }

            //拼接字符串
            $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('账号/密码错误!加密后的字符串和前端提交上来的不一样,肯定有某个地方两端没有统一');
            }

            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需要对应当前提交的类型 , POST ,PUT , DELETE , GET
function ajax(type,data={}) {
let url = 'http://your_uri/'
let path = 'api/index.php?m=web&f=authSql'   //你的请求地址

let bodyurl = "/api/index.php?m=web&f=authSql";
var userstr = encrypt('yourusername', 'yourpassword', bodyurl, type,'yourrealm');   //  yourname 和yourpassword,yourrealm是需要和后端统一才行。后端用一个表专门存这些数据
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)
}
});
})

}



//加密形成摘要的规则也需要和前端统一
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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,082评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,231评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,047评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,977评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,893评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,976评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,605评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,888评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,906评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,732评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,513评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,980评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,132评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,447评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,027评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,232评论 2 339