使用 PHP 会话和 Javascript 的 HTTP 身份验证 - 但我弄错了吗?
HTTP Authentication with PHP Sessions and Javascript - but have I got it wrong?
最后一天我一直在做 mini-project。
这是一个菜单界面,有 4 个子菜单部分。
单击每个子菜单时,都会请求单独的 HTTP 身份验证。
如果用户提交正确的身份验证,则子菜单“解锁”。否则子菜单保持锁定状态。
我已经让它工作了,我知道它为什么会工作但是-和这个是我的问题-它看起来有点hacky,我怀疑可能有更优化的解决方案。
TLDR;直接进入第六步(下)
第一步
我第一次写菜单,弹出HTTP Authentication Menu的时候,有三种结果:
- 如果用户给出了错误的响应,则再次请求身份验证
- 如果用户回答正确,子菜单解锁
- 如果用户取消...浏览器显示
401 Unauthorised Page
(当然会...)
第二步
我希望菜单对用户保持可见,所以我设置了自定义 401 Unauthorised Page
添加:
ErrorDocument 401 /my-custom-401/
到我的 .htaccess
文件
而且,由于它是一个 PHP 文件,我添加了一个位置 header 重定向:
header('Location: http://'.$_SERVER['HTTP_HOST'].'/my-menu/');
exit();
到文件的顶部。
没有。你知道那是做什么的吗?它可以防止身份验证控制台弹出。为什么?因为,在弹出控制台时,服务器已经在访问自定义 401 Unauthorised Page
(即使在您单击取消之前它不会显示在浏览器中)。因此,如果服务器看到的第一件事是位置 header,它会在弹出控制台之前离开。
第三步
所以,我写了一些 html(<head>
、<body>
等),放弃了 PHP 位置 Header 并添加了 javascript 重定向到 <head>
:
<script>window.location.href = '/my-menu/';</script>
当然更好,虽然现在,鉴于我已经解锁了子菜单(这是幕后的默认行为 - 对于所有那些已经通过身份验证并且不需要再次通过它的用户), 现在发生的是,只需在控制台上按取消,就意味着我返回到菜单,并且(当然)子菜单现在已解锁。
第四步
所以,我回到我的自定义 401 Unauthorised Page
我 re-locked 子菜单(我为不需要身份验证的用户解锁了) 在重定向之前。我正在使用 PHP 会话 ,所以它看起来像这样:
$_SESSION['My_Submenu_Unlocked'] = FALSE;
行为现在 完全符合预期 对于那些已经验证 和 尚未通过身份验证并去解锁子菜单的用户,然后:
- 输入错误的详细信息; 或
- 按取消
但对于那些输入正确详细信息的用户,尽管他们现在已经通过身份验证,但他们会被重定向回带有 $_SESSION['My_Submenu_Unlocked'] = FALSE;
标志的菜单,这意味着子菜单不会显示为已解锁。 .即使他们第二次点击它(通过身份验证),菜单也会解锁。
第五步
点击某个东西,让它什么也不做,然后在你第二次点击它时做出反应,这不是很好的用户体验。我希望子菜单在我第一次点击时解锁。我认为,要做到这一点,服务器(或浏览器)需要识别用户刚刚从自定义 401 Unauthorised Page
重定向,然后在相应的子菜单上 auto-click 自身重定向,以提供预期的行为。
auto-clicking 不是问题 - 我可以在 javascript 中使用 .click()
做到这一点。但很快就变得很明显,如果浏览器在从自定义 401 Unauthorised Page
重定向后触发 javascript 而没有进一步的条件检查 那么任何人在身份验证控制台上单击取消, 会发现自己处于身份验证请求的无限循环中,总是被重定向到菜单,然后再重定向到自定义 401 Unauthorised Page
等等...
第六步
... 就在那时,我偶然发现了什么可能是 hack,或者可能是一个优雅的解决方案,它利用了标准服务器行为,其中 PHP 首先被处理,然后服务器等待积极的用户身份验证 并且只有这样 才会将 HTML 和 CSS 以及 Javascript 传送到浏览器。
在这里。在自定义 401 Unauthorised Page
的头部顶部,我有以下 PHP、HTML 和 Javascript:
<?php
session_start();
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Custom 401 Unauthorised Page</title>
';
// CONFIRM THAT SERVER HAS VISITED "401 UNAUTHORISED" AUTHENTICATION PAGE
$_SESSION['Authorisation_Check'] = TRUE;
// AUTHORISATION INSTRUCTIONS
$_SESSION['Selected_Submenu_Unlocked'] = FALSE;
// JAVASCRIPT REDIRECT FOR WHEN AUTHENTICATIONS ARE CANCELLED BY THE USER
echo '<script>window.location.href = \'/my-menu/?locked\';</script>';
echo '
<link rel="stylesheet" href="/my-styles.css" />
</head>
';
上面 javascript 重定向中的查询字符串 ?locked
是我需要确保 auto-click 永远不会发生 返回菜单 如果 用户按下取消。为什么?因为,显然, javascript 重定向(带有查询字符串)只有在 usr 是否点击取消。
如果用户填写的认证信息正确,服务器仍然解析通过<head>
,注意:
// CONFIRM THAT SERVER HAS VISITED "401 UNAUTHORISED" AUTHENTICATION PAGE
$_SESSION['Authorisation_Check'] = TRUE;
// AUTHORISATION INSTRUCTIONS
$_SESSION['Selected_Submenu_Unlocked'] = FALSE;
但是,在用户正确响应控制台后,它 returns 在浏览器开始处理之前 URL 到菜单 URL (没有查询字符串):
// JAVASCRIPT REDIRECT FOR WHEN AUTHENTICATIONS ARE CANCELLED BY THE USER
echo '<script>window.location.href = \'/my-menu/?locked\';</script>';
我明白为什么这样做了,但这真的可靠吗?
或者这种 PHP 执行和 Javascript 执行的分离(中间有 HTTP 身份验证)是否是一种足够强大的方法,可以在将来使用和重用?
无论哪种方式,有没有更好、更优化的方法仍然使用 HTTP 身份验证 和 PHP 会话 但那不涉及这种棘手的问题 javascript?
我仍然不清楚在自定义 401 页面上使用 javascript 重定向(对于取消身份验证控制台的用户)是合法的方法还是仅仅是一种方便的 hack,但我已经暂时接受使用它。
我将其称为 Authentication Sandwich。
有用的是,我已经意识到,而不是过于复杂的过程:
- 重新锁定自定义子菜单
401 Unauthorised Page
- 标记对自定义的访问
401 Unauthorised Page
- 通过 javascript 重定向回附加了查询字符串的菜单
- 正在处理菜单页面上的条件块 if 刚刚有来自自定义
401 Unauthorised Page
. 的重定向
- 并且如果 有 ,检查是否有附加到 URL.
的查询字符串
- 如果没有,则使用javascript再次点击子菜单。
(荒谬 复杂,不是吗?)
我可以用更简单的替代方法替换以上所有内容:
自定义 401 Unauthorised Page
的 <head>
中的 javascript 重定向访问中间页面,i) 重新锁定子菜单;和 ii) returns 到菜单
就是这样。
- 无需标记对自定义的访问
401 Unauthorised Page
- 不需要任何查询字符串
- 菜单页面上不需要条件块
- 无需过于复杂地使用 javascript 即可再次单击所选子菜单
很多,很多更简单直接。
最后一天我一直在做 mini-project。
这是一个菜单界面,有 4 个子菜单部分。
单击每个子菜单时,都会请求单独的 HTTP 身份验证。
如果用户提交正确的身份验证,则子菜单“解锁”。否则子菜单保持锁定状态。
我已经让它工作了,我知道它为什么会工作但是-和这个是我的问题-它看起来有点hacky,我怀疑可能有更优化的解决方案。
TLDR;直接进入第六步(下)
第一步
我第一次写菜单,弹出HTTP Authentication Menu的时候,有三种结果:
- 如果用户给出了错误的响应,则再次请求身份验证
- 如果用户回答正确,子菜单解锁
- 如果用户取消...浏览器显示
401 Unauthorised Page
(当然会...)
第二步
我希望菜单对用户保持可见,所以我设置了自定义 401 Unauthorised Page
添加:
ErrorDocument 401 /my-custom-401/
到我的 .htaccess
文件
而且,由于它是一个 PHP 文件,我添加了一个位置 header 重定向:
header('Location: http://'.$_SERVER['HTTP_HOST'].'/my-menu/');
exit();
到文件的顶部。
没有。你知道那是做什么的吗?它可以防止身份验证控制台弹出。为什么?因为,在弹出控制台时,服务器已经在访问自定义 401 Unauthorised Page
(即使在您单击取消之前它不会显示在浏览器中)。因此,如果服务器看到的第一件事是位置 header,它会在弹出控制台之前离开。
第三步
所以,我写了一些 html(<head>
、<body>
等),放弃了 PHP 位置 Header 并添加了 javascript 重定向到 <head>
:
<script>window.location.href = '/my-menu/';</script>
当然更好,虽然现在,鉴于我已经解锁了子菜单(这是幕后的默认行为 - 对于所有那些已经通过身份验证并且不需要再次通过它的用户), 现在发生的是,只需在控制台上按取消,就意味着我返回到菜单,并且(当然)子菜单现在已解锁。
第四步
所以,我回到我的自定义 401 Unauthorised Page
我 re-locked 子菜单(我为不需要身份验证的用户解锁了) 在重定向之前。我正在使用 PHP 会话 ,所以它看起来像这样:
$_SESSION['My_Submenu_Unlocked'] = FALSE;
行为现在 完全符合预期 对于那些已经验证 和 尚未通过身份验证并去解锁子菜单的用户,然后:
- 输入错误的详细信息; 或
- 按取消
但对于那些输入正确详细信息的用户,尽管他们现在已经通过身份验证,但他们会被重定向回带有 $_SESSION['My_Submenu_Unlocked'] = FALSE;
标志的菜单,这意味着子菜单不会显示为已解锁。 .即使他们第二次点击它(通过身份验证),菜单也会解锁。
第五步
点击某个东西,让它什么也不做,然后在你第二次点击它时做出反应,这不是很好的用户体验。我希望子菜单在我第一次点击时解锁。我认为,要做到这一点,服务器(或浏览器)需要识别用户刚刚从自定义 401 Unauthorised Page
重定向,然后在相应的子菜单上 auto-click 自身重定向,以提供预期的行为。
auto-clicking 不是问题 - 我可以在 javascript 中使用 .click()
做到这一点。但很快就变得很明显,如果浏览器在从自定义 401 Unauthorised Page
重定向后触发 javascript 而没有进一步的条件检查 那么任何人在身份验证控制台上单击取消, 会发现自己处于身份验证请求的无限循环中,总是被重定向到菜单,然后再重定向到自定义 401 Unauthorised Page
等等...
第六步
... 就在那时,我偶然发现了什么可能是 hack,或者可能是一个优雅的解决方案,它利用了标准服务器行为,其中 PHP 首先被处理,然后服务器等待积极的用户身份验证 并且只有这样 才会将 HTML 和 CSS 以及 Javascript 传送到浏览器。
在这里。在自定义 401 Unauthorised Page
的头部顶部,我有以下 PHP、HTML 和 Javascript:
<?php
session_start();
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Custom 401 Unauthorised Page</title>
';
// CONFIRM THAT SERVER HAS VISITED "401 UNAUTHORISED" AUTHENTICATION PAGE
$_SESSION['Authorisation_Check'] = TRUE;
// AUTHORISATION INSTRUCTIONS
$_SESSION['Selected_Submenu_Unlocked'] = FALSE;
// JAVASCRIPT REDIRECT FOR WHEN AUTHENTICATIONS ARE CANCELLED BY THE USER
echo '<script>window.location.href = \'/my-menu/?locked\';</script>';
echo '
<link rel="stylesheet" href="/my-styles.css" />
</head>
';
上面 javascript 重定向中的查询字符串 ?locked
是我需要确保 auto-click 永远不会发生 返回菜单 如果 用户按下取消。为什么?因为,显然, javascript 重定向(带有查询字符串)只有在 usr 是否点击取消。
如果用户填写的认证信息正确,服务器仍然解析通过<head>
,注意:
// CONFIRM THAT SERVER HAS VISITED "401 UNAUTHORISED" AUTHENTICATION PAGE
$_SESSION['Authorisation_Check'] = TRUE;
// AUTHORISATION INSTRUCTIONS
$_SESSION['Selected_Submenu_Unlocked'] = FALSE;
但是,在用户正确响应控制台后,它 returns 在浏览器开始处理之前 URL 到菜单 URL (没有查询字符串):
// JAVASCRIPT REDIRECT FOR WHEN AUTHENTICATIONS ARE CANCELLED BY THE USER
echo '<script>window.location.href = \'/my-menu/?locked\';</script>';
我明白为什么这样做了,但这真的可靠吗?
或者这种 PHP 执行和 Javascript 执行的分离(中间有 HTTP 身份验证)是否是一种足够强大的方法,可以在将来使用和重用?
无论哪种方式,有没有更好、更优化的方法仍然使用 HTTP 身份验证 和 PHP 会话 但那不涉及这种棘手的问题 javascript?
我仍然不清楚在自定义 401 页面上使用 javascript 重定向(对于取消身份验证控制台的用户)是合法的方法还是仅仅是一种方便的 hack,但我已经暂时接受使用它。
我将其称为 Authentication Sandwich。
有用的是,我已经意识到,而不是过于复杂的过程:
- 重新锁定自定义子菜单
401 Unauthorised Page
- 标记对自定义的访问
401 Unauthorised Page
- 通过 javascript 重定向回附加了查询字符串的菜单
- 正在处理菜单页面上的条件块 if 刚刚有来自自定义
401 Unauthorised Page
. 的重定向
- 并且如果 有 ,检查是否有附加到 URL. 的查询字符串
- 如果没有,则使用javascript再次点击子菜单。
(荒谬 复杂,不是吗?)
我可以用更简单的替代方法替换以上所有内容:
自定义 401 Unauthorised Page
的 <head>
中的 javascript 重定向访问中间页面,i) 重新锁定子菜单;和 ii) returns 到菜单
就是这样。
- 无需标记对自定义的访问
401 Unauthorised Page
- 不需要任何查询字符串
- 菜单页面上不需要条件块
- 无需过于复杂地使用 javascript 即可再次单击所选子菜单
很多,很多更简单直接。