使用 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的时候,有三种结果

  1. 如果用户给出了错误的响应,则再次请求身份验证
  2. 如果用户回答正确,子菜单解锁
  3. 如果用户取消...浏览器显示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 Pagere-locked 子菜单(我为不需要身份验证的用户解锁了) 在重定向之前。我正在使用 PHP 会话 ,所以它看起来像这样:

$_SESSION['My_Submenu_Unlocked'] = FALSE;

行为现在 完全符合预期 对于那些已经验证 尚未通过身份验证并去解锁子菜单的用户,然后:

  1. 输入错误的详细信息;
  2. 按取消

但对于那些输入正确详细信息的用户,尽管他们现在已经通过身份验证,但他们会被重定向回带有 $_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


有用的是,我已经意识到,而不是过于复杂的过程:

  1. 重新锁定自定义子菜单 401 Unauthorised Page
  2. 标记对自定义的访问401 Unauthorised Page
  3. 通过 javascript 重定向回附加了查询字符串的菜单
  4. 正在处理菜单页面上的条件块 if 刚刚有来自自定义 401 Unauthorised Page.
  5. 的重定向
  6. 并且如果 ,检查是否有附加到 URL.
  7. 的查询字符串
  8. 如果没有,则使用javascript再次点击子菜单。

荒谬 复杂,不是吗?)

我可以用更简单的替代方法替换以上所有内容:

自定义 401 Unauthorised Page<head> 中的 javascript 重定向访问中间页面,i) 重新锁定子菜单;和 ii) returns 到菜单

就是这样。

  • 无需标记对自定义的访问401 Unauthorised Page
  • 不需要任何查询字符串
  • 菜单页面上不需要条件块
  • 无需过于复杂地使用 javascript 即可再次单击所选子菜单

很多,很多更简单直接。