我使用带有 BASIC 身份验证的码头 6.1.22 作为我的登录机制。我第一次登录 Web 应用程序时,浏览器会请求用户名和密码。
如果它尝试使用 session.invalidate() 注销,则会话无效但凭据被缓存。这意味着如果我尝试连接到安全 URL,我将看到不同的会话 ID,但没有用户名和密码对话框。
我使用带有 BASIC 身份验证的码头 6.1.22 作为我的登录机制。我第一次登录 Web 应用程序时,浏览器会请求用户名和密码。
如果它尝试使用 session.invalidate() 注销,则会话无效但凭据被缓存。这意味着如果我尝试连接到安全 URL,我将看到不同的会话 ID,但没有用户名和密码对话框。
(我意识到这个问题很老,但其他人可能想要答案)
基本身份验证实际上并不能满足您的要求,但如果您愿意忍受一些“怪癖”,您可以获得一些有点像您想要的东西。
BASIC Authentication 有两个方面使其难以以这种方式控制
这两个方面都是特性,但是它们使得将 BASIC 身份验证链接到 Java 会话变得困难。这就是为什么存在替代登录机制(如 Java FORM 登录)
BASIC Authentication 是无状态
的 这意味着客户端完全不知道服务器端发生了什么,并且它当然无法将一组 BASIC Authentication 凭据链接到 cookie(主要控制 java 会话)浏览器会在每个
请求
中简单地发送用户名+密码,直到它决定停止(通常是因为浏览器已关闭,并创建了一个新的浏览器会话)。
浏览器不知道服务器对凭据做了什么。它不知道是否需要它们,也不知道服务器端何时决定“新会话”已经开始,它只是继续发送每个请求的用户名+密码。
BASIC Authentication is Client-Side
用户/密码的对话由客户端处理。服务器只说“您请求的 URL 需要用户名+密码,我们已将此安全领域命名为 'xyz'”。
服务器不知道用户是否每次都在输入密码,或者客户端是否缓存了密码。它不知道那里是否真的有用户,或者密码是否从文件中提取出来。
服务器唯一能做的就是说“您需要在访问此 URL 之前给我一个用户+密码”
如何伪造
基本上,您需要检测(即做出有根据的猜测)浏览器何时发送旧凭据,然后再次发送“请给我一个用户+密码”响应(HTTP 401)。
最简单的方法是在您的应用程序中设置一个过滤器,用于检测用户首次登录该会话并发送401
响应代码。就像是:
if(session.getAttribute("auth") == null)
{
response.setStatus(401);
response.setHeader("WWW-Authenticate", "basic realm=\"Auth (" + session.getCreationTime() + ")\"" );
session.setAttribute("auth", Boolean.TRUE);
writer.println("Login Required");
return;
}
在那个例子中,我用会话的创建时间命名了领域(虽然它不是很漂亮——你可能想要不同的格式)。这意味着每次您使会话无效时,安全领域的名称都会发生变化,这有助于防止客户端感到困惑(为什么它再次要求我输入用户+密码,对于同一个领域,而我只是给了一个?) .
新的域名不会混淆 servlet 容器,因为它永远不会看到它 - 客户端响应不包括域名。
但诀窍在于,您不希望用户在第一次登录时被要求输入密码两次。而且,开箱即用,此解决方案将做到这一点 - 一次是容器要求它,然后当您的过滤器要求它时再次。
如何避免获得 2 个登录框 有 4 个选项。
用代码做
如果您乐于在自己的 servlet/过滤器中完成所有安全工作,并且没有从 servlet 容器(Jetty)获得帮助,那么这并不太难。您只需在 web.xml 中关闭 BASIC auth,并在代码中完成所有操作。(有相当多的工作,你需要确保你不会留下任何安全漏洞,但它在概念上很容易)
大多数人不想这样做。
辅助 Cookie
用户登录到您的应用程序后,您可以设置在浏览器会话结束时过期的 cookie(“已验证”)。此 cookie 与浏览器会话相关联,而不是与 Java 会话相关联。
当您使 Java 会话无效时 -不要使“经过身份验证的” cookie 无效。
如果用户登录到新的java 会话(即session.getAttribute("auth")==null
),但仍然具有此“身份验证”,那么您知道他们正在重新使用现有的浏览器会话并且可能正在重新使用现有的 HTTP 身份验证凭据。在这种情况下,您401
可以强迫他们提供新的凭据。
不安全的根 URL
如果您的根 URL 是不安全的,并且您知道这是您的用户始终登录的 URL,那么您只需将“auth”/401
检查放在该 URL 上,它就会解决问题。但请确保您不会意外打开安全漏洞。
除了将用户重定向到“真实”应用程序(即安全的)之外,此 URL 不应具有任何功能
单一安全 URL
有 1 个安全 URL(例如“/login”)。
除了您的“auth”/401
过滤器之外,在所有页面(登录除外)上都有另一个过滤器(或同一过滤器中的附加代码)来检查是否request.getUserPrincipal()
已设置。如果没有,将用户重定向到“/login”。
更简单的
解决方案
只需使用 FORM 登录方法而不是 BASIC 身份验证。它旨在解决这个问题。