绑定用户实体和 GlassFish 主体

2024-04-20

我有一个实体类User其中包含用户名、名字、姓氏和密码等信息,我有 GlassFish 3.1 服务器设置来执行身份验证。到目前为止,一切都很好。在容器对用户进行身份验证后,我需要某种方法将主体绑定到实际的用户实体。毕竟,GlassFish 告诉我用户“laurens”已通过身份验证,但它没有给我相应的信息User entity.

为此我编写了一个 JSF 托管 beanUserController。我想知道的是,这是否是查找实际实体的正确方法,以及是否存在我没​​有看到的明显陷阱。

UserController具有以下字段:

@EJB
private UserFacade userFacade;

private User user;

The userFacade是一个需要持久化和查找的无状态会话 beanUser实例。这userJSF 页面使用 field 来获取和设置用户的属性。

我使用以下方法来执行绑定并附带两个辅助方法:

@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);
}

这是正确的做法吗?

Thanks!

Edit:

感谢您的投入!我想了一会儿,虽然我认为将密码移动到不同的表对我来说目前处理起来有点太多,但我确实认为我可以通过分离密码来解决一些问题UserController in a @RequestScoped AuthenticationController和一个脱光的@SessionScoped UserController.

The AuthenticationController将有emailAddress and password字段,由网页的电子邮件地址和密码字段绑定。它还将包含public void authenticate()对用户进行身份验证并随后丢弃凭据。这@SessionScoped UserController然后可以绑定到适当的User实体而无需知道密码。事实上,我相信我能够从中删除密码字段User共。


您提出的方法有一些粗糙的地方,但在大多数情况下它是相当好的。

如果您打算存储对User实体,那么最好是在SessionScoped托管 bean。这有它的优点和缺点。明显的优点是

  • the User实体在整个应用程序流程中的所有页面上都可用。这意味着您需要绑定Principal to a User实体在一个会话中只能使用一次。如果需要,您可以在所有页面中重复使用绑定值。

不太明显的缺点是

  • the password字段将在内存中存储相当长的一段时间。最好的情况是,您应该在尝试身份验证后尝试使实体的密码字段无效(无论是否成功,无论该字段包含明文密码还是散列密码)。此外,定义password字段作为延迟获取(FetchType of LAZY) 与默认的 eager fetch (FetchType of EAGER)。如果您实现此操作(特别是密码字段无效),您需要注意涉及在User实体;在这种情况下,最好有一个单独的实体来存储用户的密码(非常不幸,但这就是您必须在某些应用程序中保护密码及其哈希值的程度)。

话虽如此,还需要确保以下几点:

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

Update

这是基于编辑的问题。如果您实施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 模式。我留下了一些与重定向前当前会话失效相关的代码,以防止会话固定攻击。的绑定User实体到Principal只要是在会话范围的 bean 中完成,就会在新会话中完成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

绑定用户实体和 GlassFish 主体 的相关文章

随机推荐

  • 为什么有些对象属性是 UnaryExpression,而另一些对象属性是 MemberExpression?

    根据我的答案采取行动使用 lambda 而不是字符串属性名称选择模型属性 https stackoverflow com questions 3558974 select a model property using a lambda an
  • 删除记录时找不到元素

    JqG rid 4 6 一切正常 唯一的问题是 当我打开 Firefox 调试器并转到控制台时 如果我删除一条记录 单击垃圾桶图标 然后弹出删除对话框 单击删除按钮并刷新页面等 调试器会警告我 没有找到元素 可能的脚本是 gridSelec
  • Python 中 Comet 的最新推荐? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 对 numpy 屏蔽数组的操作给出屏蔽的无效值

    来自 numpy 中屏蔽数组的文档numpy 数组上的操作 https docs scipy org doc numpy reference maskedarray generic html operations on masked arr
  • Java 中的内存管理

    如何在Java中手动删除对象 有没有类似的方法obj delete or obj kill 没有真正的办法 Java有一个特殊的垃圾收集器这会为你做到这一点 一旦您的对象没有任何对它的引用 它就会在某个时候被垃圾收集器拾取并销毁 From
  • 带有多个 webapp 的 tomcat ajp 连接器

    我有一个 tomcat 服务器 带有 webapps ROOT 应用程序 以 Apache 为前端 LoadModule proxy ajp module modules mod proxy ajp so and ProxyPass ajp
  • 如何在 Swift 中返回序列?

    我正在尝试编写一个扩展Matrix书中的例子 稍微调整为通用的 https stackoverflow com q 24136604 458193 我正在尝试编写一个名为的方法getRow返回给定行的值序列 在 C 中 我会这样写 IEnu
  • 迭代 JSON 数据? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我有一个如下所示的 JSON 数据
  • 数据源中 String 类型的给定值无法转换为指定目标列的 bigint 类型

    这是我的代码 protected void SendToServer Click object sender EventArgs e DataTable Values Session valuesdt as DataTable if Val
  • 必须在创建 QCoreApplication 之前设置属性 Qt::AA_UseSoftwareOpenGL

    所以我的环境是 Windows 10 截至 2019 年 11 月 8 日更新 通过 miniconda 安装了 Python 3 6 Spyder 4 运行 miniconda shell 激活虚拟环境 运行 Spyder 我得到以下信息
  • .PO 到 .MO - 程序转换 (PHP)

    我计划允许用户通过 PHP 用户界面生成 POT 文件 PO 文件 作为 CMS 解决方案的一部分 一旦生成这些文件 简单一点 我希望允许我的系统自动将这些文件转换为 MO 文件以响应用户 POST 请求 我在SO上看到了以下问题 php
  • InvalidArgumentError:ConcatOp:输入的维度应该匹配

    Tensorflow 1 7使用dynamic rnn时 一开始运行良好 但在第32步 当我运行代码时它发生变化 时 出现错误 当我使用较小的批次时 代码似乎可以运行更长时间 但是错误仍然弹出 只是无法弄清楚出了什么问题 from mapp
  • 一个带有一个等号的 php if 语句...?这是什么意思?

    我正在尝试解决问题 并且需要理解这个 if 语句的含义 if confirmation payment modules gt confirmation 我能找到的所有资源只显示带有双等号的 if 语句 而不是单等号 这是 php if 的简
  • 错误:没有运算符 << 与这些操作数匹配?

    我正在练习一些 C 试图离开 Java 我偶然发现了这个恼人的错误 错误 没有操作符 这个错误在我的 cpp 文件中 还有其他错误 但我现在不关心它们 void NamedStorm displayOutput NamedStorm sto
  • 是否可以在 Android Wear 上显示 Google 地图视图?

    是否可以在 Android Wear 上显示 Google 地图视图 我想在地图上向用户显示特定位置 您可以设法在您的 Activity 中嵌入 MapView 但是这是行不通的因为 Android Wear 无法直接访问网络 然而 你能做
  • 使用 ImageIO 发送图像流?

    我设置了一个 ServerSocket 和一个 Socket 因此 ServerSocket 使用 ImageIO write 发送图像流 并且 Socket 尝试读取它们并用它们更新 JFrame 所以我想知道 ImageIO 是否可以检
  • 使用 Bash 下载并在 wordpress wp-config.php 中插入盐字符串

    如何插入变量 SALT 的内容在特定点 线或串 使用 Bash 脚本从 WordPress 获取像 wp contet php 这样的文件 SALT curl L https api wordpress org secret key 1 1
  • 应用 CSS 过滤器时,内联 SVG 在 iOS 和 Safari 中消失

    情况是我有一个内联 SVG 生成的格伦蒂康 https github com filamentgroup grunticon并插入到 DOM 中 它是灰色背景上的白色 带有阴影 我对阴影使用了以下 CSS svg webkit filter
  • 在 Python 中注释函数的正确方法是什么?

    Python 中是否有一种普遍接受的注释函数的方法 以下情况可以接受吗 Create a new user def add self 正确的方法是提供文档字符串 那样 help add 也会吐出你的评论 def add self Creat
  • 绑定用户实体和 GlassFish 主体

    我有一个实体类User其中包含用户名 名字 姓氏和密码等信息 我有 GlassFish 3 1 服务器设置来执行身份验证 到目前为止 一切都很好 在容器对用户进行身份验证后 我需要某种方法将主体绑定到实际的用户实体 毕竟 GlassFish