首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用j_security_check在Java / JSF中执行用户身份验证

使用j_security_check在Java / JSF中执行用户身份验证
EN

Stack Overflow用户
提问于 2010-02-05 11:45:35
回答 4查看 149.1K关注 0票数 158

我想知道当前的方法是如何使用JSF2.0(如果存在任何组件)和Java 6核心机制(登录/检查权限/注销),并将用户信息保存在JPA实体中的web应用程序的用户身份验证。Oracle Java教程在这方面有点稀疏(只处理servlet)。

这是,没有使用整个其他框架,比如Security (acegi)或Seam,但如果可能的话,可以尝试使用新的Java 6平台( whole )。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-06-08 12:32:51

在搜索Web并尝试了许多不同的方法之后,下面是我对Java 6身份验证的建议:

设置安全域:

在我的例子中,我的数据库中有用户。因此,我按照这篇博客文章创建了一个JDBC领域,它可以根据我的数据库表中的用户名和MD5哈希密码对用户进行身份验证:

http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html

注意:文章谈到了数据库中的一个用户和一个组表。我有一个带有UserType enum属性的用户类,它通过javax.persistence注释映射到数据库。我为用户和组配置了相同的表,使用userType列作为组列,运行良好。

使用表单认证:

仍然按照上面的博客文章,配置您的web.xml和sun-web.xml,但是不要使用基本身份验证,而是使用表单(实际上,您使用的表单并不重要,但我最终使用了表单)。使用标准HTML,而不是JSF。

然后使用BalusC上面关于延迟从数据库初始化用户信息的技巧。他建议在托管bean中从faces上下文中获取主体。我使用了一个有状态会话bean来存储每个用户的会话信息,因此我注入了会话上下文:

代码语言:javascript
复制
 @Resource
 private SessionContext sessionContext;

使用主体,我可以检查用户名,并使用Entity从数据库中获取用户信息并存储在我的SessionInformation EJB中。

注销:

我还四处寻找最好的注销方式。我发现最好的方法是使用Servlet:

代码语言:javascript
复制
 @WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"})
 public class LogoutServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   HttpSession session = request.getSession(false);

   // Destroys the session for this user.
   if (session != null)
        session.invalidate();

   // Redirects back to the initial page.
   response.sendRedirect(request.getContextPath());
  }
 }

虽然考虑到这个问题的日期,我的回答真的很晚了,但我希望这能帮助其他从谷歌来到这里的人,就像我一样。

再见,

Vítor Souza

票数 86
EN

Stack Overflow用户

发布于 2010-02-05 12:31:33

我想您希望基于表单的认证使用部署描述符j_security_check

您也可以在JSF中使用与教程中演示的相同的预先定义的字段名j_usernamej_password来实现这一点。

例如。

代码语言:javascript
复制
<form action="j_security_check" method="post">
    <h:outputLabel for="j_username" value="Username" />
    <h:inputText id="j_username" />
    <br />
    <h:outputLabel for="j_password" value="Password" />
    <h:inputSecret id="j_password" />
    <br />
    <h:commandButton value="Login" />
</form>

您可以在User getter中执行延迟加载,以检查User是否已经登录,如果没有,则检查请求中是否存在Principal,如果存在,则获取与j_username关联的User

代码语言:javascript
复制
package com.stackoverflow.q2206911;

import java.io.IOException;
import java.security.Principal;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class Auth {

    private User user; // The JPA entity.

    @EJB
    private UserService userService;

    public User getUser() {
        if (user == null) {
            Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
            if (principal != null) {
                user = userService.find(principal.getName()); // Find User by j_username.
            }
        }
        return user;
    }

}

在JSF中,User显然可以通过#{auth.user}访问。

若要注销,请执行HttpServletRequest#logout() (并将User设置为null!)。您可以通过HttpServletRequest通过ExternalContext#getRequest()获得JSF中的句柄。您也可以完全使会话无效。

代码语言:javascript
复制
public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "login?faces-redirect=true";
}

对于剩余部分(在部署描述符和领域中定义用户、角色和约束),只需按照通常的方式遵循Java 6教程和remnant容器文档。

Update:您还可以使用新的Servlet3.0 HttpServletRequest#login()进行编程登录,而不是使用j_security_check,因为在某些服务器容器中,调度程序可能无法访问j_security_check。在本例中,您可以使用一个具有usernamepassword属性的完整JSF表单和一个bean,以及一个类似于以下内容的login方法:

代码语言:javascript
复制
<h:form>
    <h:outputLabel for="username" value="Username" />
    <h:inputText id="username" value="#{auth.username}" required="true" />
    <h:message for="username" />
    <br />
    <h:outputLabel for="password" value="Password" />
    <h:inputSecret id="password" value="#{auth.password}" required="true" />
    <h:message for="password" />
    <br />
    <h:commandButton value="Login" action="#{auth.login}" />
    <h:messages globalOnly="true" />
</h:form>

并且这个视图限定了托管bean的作用域,它还记得最初请求的页面:

代码语言:javascript
复制
@ManagedBean
@ViewScoped
public class Auth {

    private String username;
    private String password;
    private String originalURL;

    @PostConstruct
    public void init() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);

        if (originalURL == null) {
            originalURL = externalContext.getRequestContextPath() + "/home.xhtml";
        } else {
            String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);

            if (originalQuery != null) {
                originalURL += "?" + originalQuery;
            }
        }
    }

    @EJB
    private UserService userService;

    public void login() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();

        try {
            request.login(username, password);
            User user = userService.find(username, password);
            externalContext.getSessionMap().put("user", user);
            externalContext.redirect(originalURL);
        } catch (ServletException e) {
            // Handle unknown username/password in request.login().
            context.addMessage(null, new FacesMessage("Unknown login"));
        }
    }

    public void logout() throws IOException {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        externalContext.invalidateSession();
        externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml");
    }

    // Getters/setters for username and password.
}

这样,User就可以通过#{user}在JSF中访问。

票数 154
EN

Stack Overflow用户

发布于 2012-11-05 11:04:04

应该指出,将身份验证问题完全留给前端控制器(例如Apache服务器)并计算HttpServletRequest.getRemoteUser()是一种选择,后者是REMOTE_USER环境变量的JAVA表示。这也允许复杂的登录设计,如Shibboleth认证。通过web服务器过滤对servlet容器的请求对于生产环境来说是一个很好的设计,通常使用mod_jk进行过滤。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2206911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档