Chrome浏览器首次Basic Auth认证后后续输入凭证被忽略的问题及应用端解决方案求助
Chrome浏览器首次Basic Auth认证后后续输入凭证被忽略的问题及应用端解决方案求助
大家好,我最近遇到一个浏览器依赖的Basic Auth问题,折腾了好几个小时都没搞定,想请教下有没有应用端的可行 workaround。
问题现象
我的Web应用有这么个场景:用户第一次登录时输入了错误凭证,由于这些凭证会传给另一台服务器,不会立刻返回401;等应用发现请求失败后,下次请求会再次弹出Basic Auth提示框让用户重新输入。
这个流程在Pale Moon里完全正常——每次弹框输入新凭证,浏览器都会把新凭证发给服务器;但在Chrome和所有Chromium系浏览器里就出问题了:第一次输入的凭证像被“粘”住了一样,不管后续弹框时用户输入什么新内容,浏览器始终只会把第一次的凭证发给服务器,完全忽略后续输入的内容。
我已经尝试过的调试手段
- 动态修改Basic Auth的realm:我本来以为给realm加个随机字符串(比如当前时间戳),让浏览器以为每次都是不同的认证域,就能触发它使用新凭证,但试了之后完全没用。
- 强制每次请求都返回401:我甚至写了一段PHP代码,每次请求都直接返回401并重新设置realm,但不管用,第一次的凭证还是顽固地被反复发送:
if (!isset($_SERVER['PHP_AUTH_PW']) || $_SESSION['bauth']['reprompt'] == 2) { $_SESSION['bauth']['reprompt'] = 0; /* Reset */ $_SESSION['bauth']['realm'] = "myrealm " . time(); header("WWW-Authenticate: Basic realm=\"" . $_SESSION['bauth']['realm'] . "\""); header("HTTP/1.1 401 Unauthorized"); echo "Re-enter credentials"; } else { error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0); if ($_SERVER['PHP_AUTH_USER'] !== "done") { $_SESSION['bauth']['reprompt'] = 0; /* Reset */ $_SESSION['bauth']['realm'] = "myrealm " . time(); header("WWW-Authenticate: Basic realm=\"" . $_SESSION['bauth']['realm'] . "\""); header("HTTP/1.1 401 Unauthorized"); echo "Re-enter credentials"; } }
我还直接解码了原始的Authorization请求头确认,确实Chrome就是在重复发送第一次的凭证,和用户后续输入的内容无关。目前唯一的临时解决办法是完全关闭浏览器再重新打开,但问题会重复出现。
新发现的奇怪规律
我后来做了更细致的测试,发现Chrome对realm的内容有很奇怪的判定逻辑:
- 如果realm里加的是固定的字符串/数字(比如下面这段代码里的
12345),Chrome就能正常使用每次新输入的凭证:
<?php header("HTTP/1.1 401 Unauthorized"); header("WWW-Authenticate: Basic realm=\"" . "myrealm" . "12345" . "\""); error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0); die();
- 但如果realm里加的是
time()或者rand()生成的动态随机值,Chrome就又会“粘”住第一次的凭证,不管用户后续输入什么都没用:
<?php header("HTTP/1.1 401 Unauthorized"); header("WWW-Authenticate: Basic realm=\"" . "myrealm" . time() . "\""); error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0); die();
更奇怪的是,如果我把realm从固定字符串A改成固定字符串B,Chrome是能识别这是不同域并使用新凭证的——也就是说,它不是完全不支持realm变化,只是对带动态随机数字的realm有异常?我还没搞清楚这里的判定边界到底在哪里。
另外我也试过调换WWW-Authenticate和HTTP/1.1 401 Unauthorized的返回顺序,结果还是一样。
求助
因为浏览器是不可控的,我想问问有没有从应用端出发的解决办法,能让Chrome每次都尊重用户后续输入的新凭证,不再“粘”住第一次的内容?




