HttpServletRequest.login 不会为后续请求保持登录状态 [英] HttpServletRequest.login does not keep logged in for subsequent requests

查看:65
本文介绍了HttpServletRequest.login 不会为后续请求保持登录状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 HttpServletRequest.login(String, String) 登录后,使用下面的代码,在以下请求中,我仍然收到基本身份验证提示.为什么 login 功能在我的配置中不起作用?

我的端点:

@POST@Path("登录")@Consumes(MediaType.APPLICATION_JSON)公共无效登录(@Valid LoginRequest loginRequest){尝试 {用户用户 = userController.findUserByUsername(loginRequest.getUsername()).orElseThrow(NotFoundException::new);httpServletRequest.login(loginRequest.getUsername(), loginRequest.getPassword());日志信息(安全上下文);//现在不为空!}捕获(ServletException e){抛出新的 NotAuthorizedException(e.getMessage(), e, AuthenticationHeaderFilter.CHALLENGE);}}

还有我的jboss-web.xml

 <?xml version="1.0" encoding="UTF-8"?><jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.jboss.com/xml/ns/javaeehttp://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd"><security-domain>MyRealm</security-domain></jboss-web>

还有我的web.xml:

<auth-method>BASIC</auth-method><realm-name>MyRealm</realm-name></login-config><安全角色><角色名称>管理员</角色名称></安全角色><安全角色><角色名称>用户</角色名称></安全角色><安全约束><display-name>认证内容</display-name><web-resource-collection><web-resource-name>需要认证</web-resource-name><url-pattern>/api/*</url-pattern></web-resource-collection><身份验证约束><角色名称>用户</角色名称></auth-constraint></安全约束><安全约束><display-name>匿名内容</display-name><web-resource-collection><web-resource-name>从安全中排除</web-resource-name><url-pattern>/api/me/login</url-pattern></web-resource-collection></安全约束>

解决方案

其实就是HttpServletRequest#login 不强制要求在 HTTP 会话期间记住经过身份验证的身份(如果已经存在),并且当然不是在成功认证后应该创建一个 HTTP 会话(如果一个不存在).

从技术上讲,HttpServletRequest#login 调用直接传递到 identity store(该方法的 Javadoc 使用术语 login mechanism).身份存储是一种数据库,它通常只执行凭证验证并且不了解其环境(即不了解 HTTP 会话、远程 EJB 上下文 ID 或任何 JCA 流入安全 ID).

身份验证机制知道它的环境,这个机制是通过调用HttpServletRequest#authenticate来调用的.但是,这通常会在尚未通过身份验证时启动与用户的交互对话,如果用户碰巧通过身份验证,则不会记住会话中的身份验证身份(这恰好适用于 JBoss 的事实似乎更像是巧合而不是应该发生的事情).

尽管如此,Servlet 规范的第 13.10 节确实允许容器创建 HTTP 会话:

<块引用>

容器可能创建 HTTP 会话对象来跟踪登录状态.如果一个开发人员在用户未通过身份验证时创建会话,并且然后容器对用户进行身份验证,会话可见登录后的开发者代码必须与之前的会话对象相同在登录之前创建,以便不会丢失会话信息.

(强调我的)

但是……这篇文字是关于调用 login() 方法还是 authenticate() 方法并不太清楚.

简而言之,这是 Java EE 安全规范中的众多小漏洞之一;只是没有定义如何以编程方式使用给定的用户名/密码进行登录,并明确说明您是否希望仅针对当前请求或 HTTP 会话的其余部分进行登录.

我们希望在 Java EE 8 的 Java EE 安全 API (JSR 375) 中修复此类问题.

After logging in using HttpServletRequest.login(String, String), using the code below, on following requests I still get a Basic Authentication prompt. Why is the login function not working in my configuration?

My endpoint:

@POST
@Path("login")
@Consumes(MediaType.APPLICATION_JSON)
public void login(@Valid LoginRequest loginRequest) {
    try {
        User user = userController.findUserByUsername(loginRequest.getUsername()).orElseThrow(NotFoundException::new);
        httpServletRequest.login(loginRequest.getUsername(), loginRequest.getPassword());
        log.info(securityContext); // not null now!
    }
    catch (ServletException e) {
        throw new NotAuthorizedException(e.getMessage(), e, AuthenticationHeaderFilter.CHALLENGE);
    }
}

And my jboss-web.xml

  <?xml version="1.0" encoding="UTF-8"?>
  <jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://www.jboss.com/xml/ns/javaee
        http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
    <security-domain>MyRealm</security-domain>
  </jboss-web>

And my web.xml:

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>MyRealm</realm-name>
</login-config>

<security-role>
    <role-name>admin</role-name>
</security-role>

<security-role>
    <role-name>user</role-name>
</security-role>

<security-constraint>
    <display-name>Authenticated content</display-name>
    <web-resource-collection>
        <web-resource-name>Authentication required</web-resource-name>
        <url-pattern>/api/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>user</role-name>
    </auth-constraint>
</security-constraint>

<security-constraint>
    <display-name>Anonymous content</display-name>
    <web-resource-collection>
        <web-resource-name>Exclude from Security</web-resource-name>
        <url-pattern>/api/me/login</url-pattern>
    </web-resource-collection>
</security-constraint>

解决方案

Actually, the contract for HttpServletRequest#login does not mandate that the authenticated identity be remembered for the duration of the HTTP session (if one already exists), and certainly not that an HTTP session should be created upon successful authentication (for if one does not exist).

Technically speaking, the HttpServletRequest#login call goes straight through to the identity store (the method's Javadoc uses the term login mechanism for that). An identity store is a kind of database that typically only performs the credential validation and does not have knowledge about its environment (i.e. doesn't know about HTTP sessions, or remote EJB context IDs, or JCA inflow security IDs of whatever).

The authentication mechanism IS aware of its environment, and this one is invoked by calling HttpServletRequest#authenticate. But, this would normally be expected to start an interaction dialog with the user when not being authenticated yet, not remember the authenticated identity in the session if the user happens to be authenticated (the fact this happens to work on JBoss seems more like a coincidence than something that is supposed to happen).

That all said, section 13.10 of the Servlet spec does allow containers to create an HTTP session:

Containers may create HTTP Session objects to track login state. If a developer creates a session while a user is not authenticated, and the container then authenticates the user, the session visible to developer code after login must be the same session object that was created prior to login occurring so that there is no loss of session information.

(emphasis mine)

But... it's not overly clear if this text is in regard to calling the login() method or the authenticate() one.

In short, this is one of the many small gaps in the Java EE security spec; it's just not defined how to programmatically do a login with a given username/password and explicitly say if you want or do not want that to be for the current request only or for the remainder of the HTTP session.

We hope to fix issues like this in the Java EE Security API (JSR 375) for Java EE 8.

这篇关于HttpServletRequest.login 不会为后续请求保持登录状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆