[英]How to force Jetty to ask for credentials with BASIC authentication after invalidating the session?
我正在使用带有BASIC身份验证的jetty 6.1.22作为我的登录机制。 我第一次登录Web应用程序时,浏览器会请求用户名和密码。
如果它尝试使用session.invalidate()注销,则会话无效但凭据将被缓存。 这意味着如果我尝试连接到安全URL,我将看到不同的会话ID,但没有用户名和密码的对话框。
(我意识到这个问题已经过时了,但这是其他人可能想要回答的问题)
BASIC身份验证并不能真正满足您的要求,但如果您愿意接受某些“怪癖”,您可以获得一些有点像您想要的东西。
BASIC身份验证有两个方面,这使得很难以这种方式进行控制
这两个方面都是功能,但它们使得很难将BASIC身份验证链接到Java会话。 这就是备用登录机制(如Java FORM登录存在)的原因
BASIC身份验证是无状态的
这意味着客户端完全不知道服务器端发生了什么,它当然无法将一组BASIC身份验证凭据链接到cookie(这主要是控制java会话)
发生的情况是,浏览器只会在每次请求时发送用户名+密码,直到它决定停止(通常是因为浏览器已关闭,并且创建了新的浏览器会话)。
浏览器不知道服务器使用凭据做了什么。 它不知道是否需要它们,并且它不知道服务器端何时确定“新会话”已经开始,它只是继续发送每个请求的用户名+密码。
BASIC身份验证是客户端
用户/密码的对话框由客户端处理。 所有服务器都说“您请求的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身份验证。 它旨在解决这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.