java - session 无效后,如何强制Jetty使用BASIC身份验证要求凭证?

标签 java authentication jetty basic-authentication

我使用带有BASIC身份验证的 jetty 6.1.22作为我的登录机制。第一次登录Web应用程序时,浏览器会请求用户名和密码。

如果尝试使用session.invalidate()注销,则该 session 无效,但凭据被缓存。这意味着,如果我尝试连接到安全的URL,将看到不同的 session ID,但没有显示用户名和密码的对话框。

最佳答案

(我知道这个问题很旧,但这是其他人可能想要回答的问题)

BASIC身份验证实际上并不能满足您的要求,但是如果您愿意接受一些“怪癖”,则可以得到与您想要的功能类似的功能。

BASIC身份验证具有两个方面,因此很难通过这种方式进行控制

  • 这是无状态的
  • 是客户端

  • 这两个方面都是功能,但是它们使将BASIC身份验证链接到Java session 变得很困难。这就是为什么存在其他登录机制(如Java FORM登录)的原因

    BASIC身份验证是无状态的
    这意味着客户端绝对不知道服务器端正在发生什么,并且它当然无法将一组BASIC身份验证凭据链接到cookie(这主要是控制Java session 的原因)
    发生的结果是,浏览器将仅随每个请求发送用户名+密码,直到决定停止为止(通常是因为浏览器已关闭,并且创建了新的浏览器 session )。
    浏览器不知道服务器正在使用凭据做什么。它不知道是否需要它们,并且不知道服务器端何时确定“新 session ”已经开始,它只是继续在每个请求中发送该用户名+密码。

    BASIC身份验证是客户端
    用户/密码对话框由客户端处理。服务器只说“您请求的URL需要用户名+密码,并且我们已将此安全领域命名为'xyz'”。
    服务器不知道用户是否每次都输入密码,或者客户端是否已缓存密码。它不知道那里是否真的有用户,或者密码是否从文件中拉出。
    服务器唯一可以做的就是说“访问此URL之前,需要给我一个用户名和密码”

    如何伪造
    本质上,您需要检测(即做出有根据的猜测)浏览器何时发送旧凭据,然后再次发送“请给我一个用户名和密码”响应(HTTP 401)。

    最简单的方法是在您的应用程序中具有一个筛选器,该筛选器可以检测用户首次登录该 session 并发送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;
        }
    

    在该示例中,我使用 session 的创建时间来命名该领域(尽管它不是很漂亮-您可能希望采用不同的格式)。这意味着每次您使 session 无效时,安全领域的名称都会更改,这有助于防止客户端感到困惑(为什么当我只给同一个领域时,为什么再次要求我提供用户名和密码?) 。
    新的领域名称不会混淆servlet容器,因为它永远不会看到它-客户端响应不包括领域名称。

    诀窍在于,您不希望用户在首次登录时被要求两次输入密码。而且,开箱即用的解决方案将做到这一点-一次让容器要求它,然后当过滤器再次要求它时。

    如何避免获得2个登录框
    有4个选项。
  • 用代码完成所有操作。
  • 使用辅助 session cookie尝试确定用户是否是第一次登录。
  • 使您的根URL不安全(但不执行任何操作)
  • 使您的所有应用程序(除1页之外)均不受安全保护,如果未登录,则将用户重定向到该页面。

  • 用代码进行操作

    如果您乐于在自己的servlet/过滤器中进行所有安全性操作,并且没有从servlet容器(Jetty)获得帮助,那不是很困难。您只需在web.xml中关闭BASIC身份验证,然后全部通过代码完成即可。 (有很多工作要做,您需要确保不会留下任何安全漏洞,但是从概念上讲这很容易)
    大多数人都不想这样做。

    辅助Cookie
    用户登录到您的应用程序后,您可以设置一个cookie(“已认证”),该cookie在浏览器 session 结束时到期。此cookie绑定(bind)到浏览器 session ,而不是绑定(bind)到Java session 。
    使Java session 无效时-请勿使“已验证”的cookie无效。
    如果用户登录到新的Java session (即session.getAttribute("auth")==null),但仍然具有此“身份验证”,则您知道他们正在重新使用现有的浏览器 session ,并且可能正在重新使用现有的HTTP身份验证凭据。
    在这种情况下,您可以执行401技巧来强制他们提供新的凭据。

    不安全的根URL
    如果您的根URL不安全,并且您知道这是用户始终登录的URL,则只需将“auth”/401检查放在该URL上,即可解决问题。
    但是请确保您不会意外地打开安全漏洞。
    除了将用户重定向到“真实的”应用程序( protected )外,此URL不应具有任何功能。

    单个安全URL
    有1个 protected 网址(例如“/login”)。
    与“auth”/401过滤器一样,在所有页面(登录除外)上都有另一个过滤器(或同一过滤器中的其他代码),以检查是否设置了request.getUserPrincipal()。如果不是,则将用户重定向到“/登录”。

    更简单的解决方案
    只需使用FORM登录方法而不是BASIC身份验证即可。旨在解决此问题。

    关于java - session 无效后,如何强制Jetty使用BASIC身份验证要求凭证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2180206/

    相关文章:

    java - 从 php 脚本解析 Json

    java - 尽管设置了属性,但 AppCompat 工具栏标高缺失(使用 RecyclerView)

    无需身份验证的 MySQL 性能

    php - CURL 登录并提交另一个帖子

    java - 无法发送消息 : SocketTimeoutException : NotAuthorizedException

    java - Jetty + 程序化 SPNEGO 配置

    ubuntu - ubuntu 12.10 上的 jetty 等环境

    java - 从 requestContext 获取完整路径 RESTEasy3.0.7 PreRequestFilter for Security in JAVA

    JAVA IO - 请澄清

    ruby-on-rails - 为登录用户设计忘记密码