我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

401状态码是一个非常神奇的状态码,可以通过客户端出现的一个登陆用户名和密码,来完成一套realm登陆体系的认证。本文从php的代码层面上来分析一下这个realm认证协议的过程。

苏南大叔:php如何处理401状态码,完成Basic realm授权认证闭环? - php-401
php如何处理401状态码,完成Basic realm授权认证闭环?(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验总结。本文测试环境:win10nginx@1.15.11php@8.2.9ntschrome@121.0.6167.140

写在前面

不仅是phpnginx也可以发出和处理401状态码的realm认证。可以参考:

然而,这个401状态码的认证,需要浏览器来完成对应的登录框的弹出。并不是所有的浏览器都会弹出登录框[大多数会正确弹出],不同的浏览器弹出的框框也不是统一的样式。比如:electron作为一种变种的浏览器,是需要做特殊编程处理,才能够处理401状态的。参考文章:

本文是以最新的chrome浏览器为客户端的,可以正确处理401请求,以完成业务闭环。

发出需要认证请求

header('WWW-Authenticate: Basic realm="My Realm Name"');
header('HTTP/1.0 401 Unauthorized');

苏南大叔:php如何处理401状态码,完成Basic realm授权认证闭环? - 登录框
php如何处理401状态码,完成Basic realm授权认证闭环?(图3-2)

接收用户名密码

所有需要的信息,都存在于$_SERVER变量中,有:

  • 提交的用户名:$_SERVER['PHP_AUTH_USER']
  • 提交的密 码:$_SERVER['PHP_AUTH_PW']
  • 一个未知变量:$_SERVER["HTTP_AUTHORIZATION"]

苏南大叔:php如何处理401状态码,完成Basic realm授权认证闭环? - 登陆成功
php如何处理401状态码,完成Basic realm授权认证闭环?(图3-3)

完整代码

$username = @trim($_SERVER['PHP_AUTH_USER']);
$password = @trim($_SERVER['PHP_AUTH_PW']);
if ($username == "admin" && $password == "password") {
    echo "<p>欢迎您,{$_SERVER['PHP_AUTH_USER']}</p>";
    var_dump($_SERVER["HTTP_AUTHORIZATION"]);
} else {
    auth();
    // if ($username == "" || $password == "") {
    //     echo "用户名密码不能为空";
    // } else {
    //     echo "用户名密码错误";
    // }
}
function auth() {
    header('WWW-Authenticate: Basic realm="My Realm Name"');
    header('HTTP/1.0 401 Unauthorized');
    echo '点击取消按钮之后显示这句话';
}

思考一,realm名称

客户端和服务端进行交互,除了传统的getpost之类的网页可控的内容外,还有个被遗忘的角落,就是这个header交互。本文中,服务器端在发送传统的网页内容的同时,在最顶部发送了一个401状态码。401状态码被浏览器正确处理后,就会在页面渲染前弹出个样式不统一的登录框。

关于"My Realm Name"字样,在古老的浏览器上,它是会被显示出来的。但是,近年的浏览器并不显示这些字样了。

思考二,鉴权加密解密

从原理上来说,客户端实际上发送了一个header头,名叫Authorization。在php那边,从所有headers里面,得到的就是HTTP_AUTHORIZATION

它的内容以开头,表明协议方式是realm。后面的YWRtaW46cGFzc3dvcmQ=就是个base64编码了。它解码之后的内容是“admin:password”,就是客户在登录框里面输入的内容。所以,如果使用代码去模拟这个过程的话,该怎么操作,大家都明白了吧?

思考三,变量获取方式

数据是通过header从客户端传递的,$_SERVERS是将经过php加工过的。header是每次提交的结果展示,$_SERVERS是经过不断整理汇总的结果。虽然两者数据有重叠,但是还是有区别的。

变量
getallheaders()["Authorization"]Basic YWRtaW46cGFzc3dvcmQ=
$_SERVER["HTTP_AUTHORIZATION"]Basic YWRtaW46cGFzc3dvcmQ=

参考文章:

总结

实际效果上来看,这个realm方式,毕竟登录框逻辑是由浏览器所控制的。所以,相比较传统的表单登陆方式,它就显得不够灵活方便。
另外,401状态码是个非常有故事的状态码,如果一个网站可以任意调用其它网站的资源(比如图片)。那么,理论上来说,这个网站就可以被401状态码攻击利用。这里不多说,懂的都懂。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php