绑定用户实体和GlassFish Principal

我有一个实体类User ,它包含用户名,名字,姓氏和密码等信息,并且我的GlassFish 3.1服务器设置可以执行身份验证。 到现在为止还挺好。 容器验证用户后,我需要一些方法将主体绑定到实际的用户实体。 毕竟,GlassFish告诉我,用户“劳伦斯”已经过身份验证,并不是给我相应的User实体。

为此,我编写了一个JSF托管bean UserController 。 我想知道的是,如果这是查看实际实体的正确方法,以及是否有任何明显的陷阱我没有看到。

UserController具有以下字段:

@EJB
private UserFacade userFacade;

private User user;

userFacade是一个无状态会话bean,用于保存并查找User实例。 user字段由JSF页面用于获取和设置用户属性。

我使用以下方法执行绑定,并伴随着两​​个辅助方法:

@PostConstruct
private void init() {
    try {
        user = userFacade.find(getUserPrincipal().getName());
    } catch (NullPointerException ex) {
        // Intentionally left empty -- User is not logged in.
    }
}

private HttpServletRequest getHttpServletRequest() {
    return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}

private Principal getUserPrincipal() {
    return getHttpServletRequest().getUserPrincipal();
}

JSF页面使用以下方法确定要显示哪些组件(如果用户已经通过身份验证,则不需要显示登录表单),如果单击“登录”按钮以验证用户,或者注册为新的用户点击“注册”按钮时。

public boolean isAuthenticated() {
    return getUserPrincipal() != null;
}

public void authenticate() {
    try {
        getHttpServletRequest().login(user.getEmailAddress(), user.getPassword());
    } catch (Exception ex) {
        // TODO: Handle failed login attempt
    }
}

public void register() {
    userFacade.create(user);
}

这是否是正确的方式?

谢谢!

编辑:

感谢您的输入! 我想了一下,虽然我认为将密码移动到不同的表格对于我来说目前处理得有点多,但我认为我可以通过在@RequestScoped分离UserController来解决一些问题AuthenticationController和一个精简的@SessionScoped UserController

AuthenticationController将具有emailAddresspassword字段,由网页的emailAddress和密码字段绑定。 它还会包含public void authenticate()来验证用户身份,然后丢弃凭证。 @SessionScoped UserController然后可以绑定到适当的User实体,而不需要知道密码。 事实上,我相信我将能够从User一起删除密码字段。


你提出的方法有一些粗糙的边缘,但大多数情况下它很好。

如果您打算存储对User实体的引用,那么最好在SessionScoped托管bean中这样做。 这有利有弊。 显而易见的优点是

  • User实体通过应用程序流遍历所有页面。 这意味着您只需将会话的Principal绑定到User实体一次。 如果需要,您可以通过所有页面重新使用绑定值。
  • 不那么明显的缺点是

  • password字段将存储在内存中相当长的时间。 充其量,在尝试进行身份验证(无论是否成功,无论该字段是否包含明文或散列密码)时,您都应尝试取消实体的密码字段。 另外,将password字段定义为FetchType fetched( FetchType of LAZY ),而不是默认的FetchTypeEAGER FetchType )。 如果您执行此操作(特别是取消密码字段),则需要注意涉及在User实体上执行的合并操作的问题; 在这种情况下,让一个单独的实体为用户存储密码可能会更好(非常不幸,但这是在某些应用程序中必须弯腰以保护密码和哈希的程度)。
  • 话虽如此,还有必要确保以下几点:

  • 匿名用户负责人应该谨慎处理。 如果您没有编写一个过滤器来强制实施访问控制机制来保护应用程序的“私人”页面,那么您应该更多地关注页面中授权逻辑的构建方式,而不是您不必担心所有当你使用过滤器。 匿名主体就像任何其他主体一样,只是它不受领域中的身份支持。 如果Principal to User实体绑定方案出于某种原因失败,则必须使会话无效并将用户重定向到登录页面,特别是如果您的页面依赖User实体而不是Principal对象来强制进行访问控制检查。
  • 确保您有一个单独的应用程序登录页面。 这在大多数接受登录页面中的表单接受用户凭证的应用程序中更为可取; 如果表单处于对话框或其他一些工具中,则单独的登录页面通常不是必需的。 这很可取,原因很简单,您希望您的登录过程实现POST-REDIRECT-GET模式 - 成功登录到应用程序的用户必须重定向到应用程序的主页面。 如果不这样做,将导致浏览器刷新(由任何有权访问终端的人员执行)将重新提交凭证的情况; 很显然,使用模态对话框或类似的应用程序不太容易受到这个问题的影响。
  • 更新

    这是基于编辑的问题。 如果按照建议实施authenticate方法,则只有在成功验证后,才能实现将User实体绑定到Principal方案。

    以下是我的应用程序中的类似实现的复制:

    public String authenticate()
    {
        String result = null;
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
        try
        {
            request.login(userId, password);
            result = "/private/MainPage.xhtml?faces-redirect=true";
        }
        catch (ServletException ex)
        {
            logger.error("Failed to authenticate user.", ex);
            FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, Messages.getString("Login.InvalidIdOrPasswordMessage"), null);
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        }
        return result;
    }
    

    这是从facelet调用的:

    <h:form id="LoginForm" acceptcharset="UTF-8">
        <p>
            <h:outputLabel for="userid" value="#{msg['Login.userid.label']}" />
            <h:inputText id="userid" value="#{loginBean.userId}" />
        </p>
        <p>
            <h:outputLabel for="password" value="#{msg['Login.password.label']}" />
            <h:inputSecret id="password" value="#{loginBean.password}" />
        </p>
            <h:commandButton id="submit" value="#{msg['Login.submit.label']}"
                action="#{loginBean.authenticate}" />
    </h:form>
    

    注意在验证成功的情况下使用POST-REDIRECT-GET模式。 在重定向之前,我留下了一些与当前会话失效相关的代码,以防止会话修复攻击。 只要在会话范围的bean中完成, User实体与Principal的绑定将在新会话中完成。

    链接地址: http://www.djcxy.com/p/8649.html

    上一篇: Binding a User entity and a GlassFish Principal

    下一篇: Java implementation of singular value decomposition for large sparse matrices