在日常开发中,我们登录用户的时候,大多数情况下,我们会使用session来保存用户登录信息,并以此作为判断用户是否登录的依据。但其实HTTP也提供了这种登录认证机制。今天我们就来了解一下HTTP认证。HTTPBasicif(!isset($_SERVER['PHP_AUTH_USER'])){header('WWW-Authenticate:Basicrealm="MyRealm"');header('HTTP/1.0401未经授权');echo'如果用户点击取消按钮发送的文本';exit;}else{echo"
你好{$_SERVER['PHP_AUTH_USER']}.
";echo"您输入了{$_SERVER['PHP_AUTH_PW']}作为您的密码。
";}//授权:基本YWFhOmFhYQ==echobase64_decode('YWFhOmFhYQ==');//aaa:aaa等于明文还是直接从代码开始,上面的代码是最简单的一种HTTP认证方式,如果$_SERVER['PHP_AUTH_USER']不存在,那么我们会向浏览器发送一个401响应头,告诉我们需要登录认证的浏览器。当浏览器收到这个响应头时,会弹出浏览器自带的验证框,要求输入用户名和密码。当我们填写用户名和密码时,浏览器会在请求头中带上Authorization字段,将用户名和密码进行base64后发送。同时PHP会将用户名和密码分别解析成\$_SERVER['PHP_AUTH_USER']和$_SERVER['PHP_AUTH_PW']。上面的认证方式是最简单的HTTPBasic认证。可以看出,该方法中认证的用户名和密码其实相当于明文传输,因为base64很容易被逆向解析。所以这种方式是非常不安全的。那么有没有更复杂的方法呢?既然HTTPDigest是这么写的,那肯定有更好的办法,那就是HTTPDigest方式的HTTP认证。$realm='Restrictedarea';//user=>password$users=array('admin'=>'mypass','guest'=>'guest');//指定Digest认证方式if(empty($_SERVER['PHP_AUTH_DIGEST'])||!$_COOKIE['登录']){setcookie('登录',1);//退出登录条件判断header('HTTP/1.1401Unauthorized');header('WWW-Authenticate:Digestrealm="'.$realm.'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');//如果用户在没有输入密码的情况下单击取消。die('您点击了取消,无法登录');}//验证用户登录信息');}//验证登录信息$A1=md5($data['username'].':'.$realm.':'.$users[$data['username']]);$A2=md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);$valid_response=md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);//$data['response']为浏览器客户端的加密内容if($data['response']!=$valid_response){die('WrongCredentials!');}//用户名和密码验证成功echo'您的登录用户是:'.$data['username'];setcookie("login",2);//授权:Digestusername="guest",realm="Restrictedarea",nonce="5e815bcbb4eba",uri="/",response="9286ea8d0fac79d3a95fff3e442d6d79",opaque="cdce8a5c95a1427d74df7acbf41c9ce0",qop=auth,nc=00000002,cnonce="a42e137359673851"//服务器回复Thenoncevalueinthemessage,plususername,password,httpmethod,httpuriusesMD5(orotheralgorithmspecified由服务器)计算出request-digest作为repsonse头字段的值//获取登录信息functionhttp_digest_parse($txt){//echo$txt;//防止丢失数据$needed_pa??rts=array('nonce'=>1,'nc'=>1,'cnonce'=>1,'qop'=>1,'username'=>1,'uri'=>1,'响应'=>1);$数据=数组();$keys=implode('|',array_keys($needed_pa??rts));preg_match_all('@('.$keys.')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',$txt,$matches,PREG_SET_ORDER);foreach($matchesas$m){$data[$m[1]]=$m[3]?$m[3]:$m[4];unset($needed_pa??rts[$米[1]]);}返回$needed_pa??rts?false:$data;}if($_GET['注销']){setcookie("登录",0);header("Location:/");}从代码量可以看出这个方法要复杂很多。首先,我们还需要在未登录时返回一个401响应头,告诉浏览器我们要进行Digest认证。这里的头信息是不一样的。格式是Digest,内容比Basic多很多。这些额外的内容是我们在验证认证内容时需要用到的。然后,浏览器也会弹出一个弹窗,输入用户名和密码。然后提交加密后的用户名和密码信息。我们可以看到返回值中有明文用户名,但是没有明文密码。其实密码是对username、password、nonce、nc、cnoce、cop、$_SERVER['REQUEST_METHOD']、uri等进行md5加密后生成的,在response字段中提交。我们还需要按照相同的规则获取加密后的密码,并进行比较,确定用户名和密码是否正确,以便用户完成正常的登录过程。在这段代码中,我们添加了一个cookie,用于判断登出。因为这种HTTP认证方式的过期时间是基于浏览器的。即如果客户端关闭浏览器,则保存在客户端浏览器内存中的用户名和密码将消失。在这种情况下,我们只能通过cookies登出。如果用户登出,改变cookie的内容,重新发送401响应头给浏览器请求重新登录。综上所述,HTTP认证这个操作在我们日常开发中一般不会作为一个正常的登录功能来使用。大多数情况下,我们会在后台加一层HTTP认证或者一些特殊的管理工具来实现双重认证。即保证后台数据的安全。例如,我将在我的phpMyAdmin中添加一层此身份验证。另外,HTTP认证也可以直接在Nginx或Apache中配置,无需走PHP层。这个我们以后学习Nginx的时候再解释。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/PHP%E7%9A%84HTTP%E9%AA%8C%E8%AF%81.php参考文档:https://www.php.net/manual/zh/features.http-auth.php各媒体平台均可搜索【硬核项目经理】