【问题标题】:JSF / primefaces Session - Session gets lostJSF / primefaces 会话 - 会话丢失
【发布时间】:2015-04-18 00:49:39
【问题描述】:

我是 JSF 编程的新手,我的登录/会话出现问题,登录后会丢失。

我想实现一个简单的登录,用户可以输入用户名和密码。于是我写了一个LoginController:

@ManagedBean
@SessionScoped
public class LoginController extends AbstractController{

     @PostConstruct
    public void initialiseSession() {
        FacesContext.getCurrentInstance().getExternalContext().getSession(true);
    }

    private String username = "null";
    private String password;
    private boolean loggedIn = false;

    @Inject 
    private EmployeeService employeeService;


    public static final String employeeSessionKey = "user";

    public LoginController() {

    }

    public String login() {
//check username and password and if true redirect to "/"
}

我的 login.xhtml 看起来像:

<h:form id="loginForm">

            <h:outputLabel style="font-size:24px" value="Bitte melden Sie sich an!"/>

            <p:panelGrid columns="2">

                <p:outputLabel id="userOutput"  for="userInput" value="Benutzername"/>
                <p:inputText id="userInput" value="#{loginController.username}"></p:inputText>
                <p:outputLabel id="passwordOutput" for="passwordInput" value="Passwort"/>
                <p:inputText id="passwordInput" type="password" value="#{loginController.password}"></p:inputText>

                <h:outputText value="Logindaten merken?" id="outputRememberLogin">
                    <p:selectBooleanCheckbox id="loginCheckbox">
                    </p:selectBooleanCheckbox>
                    <p:spacer width="10" id="loginFormLittleSpacer"></p:spacer>
                </h:outputText>

                <p:commandButton id="loginButton" value="Anmelden" action="#{loginController.login()}" ajax="false" >
                </p:commandButton>
            </p:panelGrid>
        </h:form>  

所以当我登录时重定向工作。但是当我转到另一个 .xhtml 页面时,会话会丢失。

为了测试这个,我放了

<p:outputLabel value="#{loginController.username}"/>

在我的页面上。登录后,用户名变为“null”。

这个问题我快疯了。

有什么想法吗?

之前谢谢。

【问题讨论】:

  • 在 JSF 托管 bean 中使用 CDI 工件 @Inject 是一种不可靠的方式。
  • 为什么需要@PostConstruct注解的方法中的这一行FacesContext.getCurrentInstance().getExternalContext().getSession(true);? (您还应该避免在用户会话中保存密码)。
  • 我只是临时保存用户密码以满足测试需要。我添加了行 FacesContext.getCurr... 因为另一个页面上的错误:javax.el.MethodNotFoundException: Method not found: class de.baol.itech.javaee.view.controller.LoginController.initialiseSession()
  • 这条消息javax.el.MethodNotFoundException: Method not found 暗示您正在尝试通过EL 访问带有@PostConstruct 修饰的方法initialiseSession()。不需要通过 EL 访问带有 @PostConstruct 注释的方法。避免它也删除这条线FacesContext.getCurrentInstance().getExternalContext().getSession(true);,这也是多余的。选择不同的方式来模拟登录场景。
  • 你的@SessionScoped是从哪个包导入的?

标签: jsf session jsf-2 primefaces login


【解决方案1】:

您的LoginController bean 看起来它的注释没问题,并且代码看起来应该可以工作。但是,您可能还需要检查其他几件事。其中一些可能很明显,但您的问题缺少一些细节,所以我不确定您可能拥有什么级别的经验以及从哪里开始回答这个问题。因此,我从头开始(几乎)......


1.域名配置

要使用会话,您必须使用限定域名。向 IP 地址发送请求将不允许会话工作,因为客户端浏览器仅将会话信息发送到完全限定的域名 (http://example.com/)。如果您使用 IP(例如“http://127.0.0.1:8080/MyApp”)调用 Web 应用程序,则会话数据将永远不会发送到您的 Web 应用程序,并且您将在每个请求中创建一个新会话。确保对应用程序的每个请求都使用完全限定的域名和路径,例如“http://localhost:8080/MyApp”。


2。应用配置

检查您的 Web 应用程序的 &lt;session-config&gt; 配置是否设置正确。默认配置应该允许您的代码在无需添加任何特定内容的情况下工作,因此如果您没有添加任何内容,请不要担心这一点。但是,您可能需要确保没有任何东西会阻止会话被重用。

  • 应启用会话 cookie (&lt;tracking-mode&gt;COOKIE&lt;/tracking-mode&gt;)
  • 超时时间应该足够长,不会在第二个请求之前过期 (&lt;session-timeout&gt;60&lt;/session-timeout&gt;)
  • 应正确设置 cookie 路径以供您使用 (&lt;path&gt;/&lt;/path&gt;)

以下是我常用的会话配置……

<session-config>
    <session-timeout>60</session-timeout>  
    <tracking-mode>COOKIE</tracking-mode>
    <cookie-config>
        <path>/</path>                       
        <http-only>true</http-only> 
        <secure>false</secure>
    </cookie-config>
</session-config>

3.客户端会话 Cookie 跟踪

如果以上几点不能解决问题,您可以通过监控您的应用和客户端浏览器之间的请求和响应流量来真正开始深入了解会话跟踪。会话信息由名为“JSESSIONID”的 cookie(如果禁用 cookie,则为查询字符串参数)来回传递。它的值将是唯一会话的 ID,并且对于每个请求必须相同,以确保您的 Web 应用程序跟踪相同的会话。下面重点介绍了一些要寻找的东西……

确保“JSESSIONID”会话 cookie 已正确发送到客户端浏览器,并随着每个后续请求发送回。您可以使用 Chrome 或 Safari 的网络开发工具(在“网络”选项卡下)或使用单独的实用程序(例如 Wireshark)来执行此操作。

  • 确保“JSESSIONID”cookie 存在于第一个请求的响应中……这会让您知道您的 Web 应用程序至少正在创建会话和响应 cookie。
  • 确保来自客户端浏览器的第二个请求将“JSESSIONID”cookie 传回...这是您的网络应用知道要使用哪个现有会话的唯一方法。
  • 确保“JESSIONID”cookie 的路径为“/”(在浏览器中可能显示为“N/A”)或您的 Web 应用程序的路径(例如“/MyApp”)……客户端浏览器只会将 cookie 发送到与每个相关的域和路径。例如,如果您的登录页面是'http://example.com/MyApp/login',则'JSESSIONID' cookie 的路径可能是'/MyApp'(默认),如果向'http://example.com/'发出以下请求,则不会返回该路径(没有“/MyApp”路径)。默认路径是您的 Web 应用程序的名称(‘/MyApp’),可以使用上面指出的 &lt;path&gt; 配置项进行更改。

4. Bean 中的会话管理(附加信息)

在您的initialiseSession() 方法中,FacesContext.getCurrentInstance().getExternalContext().getSession(true); 返回的会话对象没有被保存,这一行基本上什么也没做。 @SessionScoped 注释将已经创建了一个会话,并在调用 initialiseSession() 之前将“JSESSIONID”cookie 添加到响应中。因此,调用getSession(true) 的唯一原因是,如果您想将会话保存到 bean 中的私有对象,就像这样......

@ManagedBean
@SessionScoped
public class LoginController extends AbstractController{

    // Create a global, private member for storing the session data...
    private HttpSession session;

    @PostConstruct
    public void initialiseSession() {
        // Assign the session to the global member…
        session = FacesContext.getCurrentInstance().getExternalContext().getSession(true); 
    }

…

同样,在您的示例中不需要调用getSession(true),因为SessionScoped bean 已经创建了会话。仅当您打算更新或使用会话对象时,才需要上述代码,例如添加属性或修改设置。


总结

仔细检查上述第 1 - 3 点。我的假设是“JSESSIONID”cookie 不会在后续请求中被发回。如果您可以确认每个请求中都包含“JSESSIONID”cookie(具有相同的值),则问题与会话无关,可能与您的 login() 方法中的代码有关。

【讨论】:

  • &lt;tracking-mode&gt;COOKIE&lt;/tracking-mode&gt; 需要符合 Servlet 3.0(或更高版本)的容器。
  • 支持// Create a global, private member for storing the session data... private HttpSession session;的胖子-1。你在这里犯了一个重大的设计/思维错误。
猜你喜欢
  • 1970-01-01
  • 2013-08-10
  • 2012-05-09
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多