使用Servlet 3.0编程控制登录

6
我已经测试了Glassfish 3.0.1中默认的安全容器,并得出结论,我不想再花时间在那上面了。相反,我想要自己控制验证。但是,我需要一些指导来帮助我正确地操作。

目前,我有一个UserBean,其中包含登录/注销功能(请参见下文)。我不想使用内置的*j_security_check*容器,而是使用核心JSF 2.0。

我的问题如下:

  1. 如果用户未登录(访问某些文件夹),我需要一个ServletFilter来重定向流量吗?
  2. 用户成功登录后,如何存储用户Pricipals?

感谢任何帮助或示例链接,问候Chris。

PS:抱歉将两个问题合并在一起

@ManagedBean
@SessionScoped
public class UserBean {

private AuthenticateUser authenticateUser;
...

public String login() {
    FacesContext context = FacesContext.getCurrentInstance();
    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();

    JsfUtil.log("Username : " +authenticateUser.getUserName());
    JsfUtil.log("Password : " +authenticateUser.getPassword());
    AuthenticateUser authRequest = authenticationFacade.find(authenticateUser);
    try {
        if(!authRequest.equals(authenticateUser))
            return "/loginError";

        request.login(authenticateUser.getUserName(), authenticateUser.getPassword());
        return "";
    } catch(ServletException e){
       JsfUtil.addErrorMessage(e, "Incorrect username or password, please try again.");
       return "/loginError";
    }

...
public String logOut() {
    String result = "/index?faces-redirect=true";
    FacesContext context = FacesContext.getCurrentInstance();
    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();

    try {
        request.logout();
    } catch (ServletException e) {
        JsfUtil.log("Failed to logout user!" +e.getRootCause().toString());
        result = "/loginError?faces-redirect=true";
    }
    return result;
    }
2个回答

9
当您想使用request.login()时,应该已经在容器中配置了代表用户数据库的Realm。但是您似乎已经用AuthenticationFacade替换了Realm。在这种情况下,request.login()对您没有用处。
您只需要将用户放入会话范围并拦截即可。以下是一个示例:
@ManagedBean
@SessionScoped
public class UserManager {

    @EJB
    private UserService userService;
    private String username;
    private String password;
    private User current;

    public String login() {
        current = userService.find(username, password);

        if (current == null) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Unknown login, try again"));
            return null;
        } else {
            return "userhome?faces-redirect=true";
        }
    }

    public String logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "index?faces-redirect=true";
    }

    public boolean isLoggedIn() {
        return current != null;
    }

    // Getters/setters (but do NOT provide a setter for current!)
}

当像这样手动进行身份验证时,您肯定需要使用过滤器来限制访问。如果使用容器管理的安全性,则通常会将其指定为<security-constraint><url-pattern>。但是如果没有它,您必须自己处理。了解JSF管理的bean是通过它们的bean名称在任何作用域中进行键控的,这很有帮助。

UserManager userManager = ((HttpServletRequest) request).getSession().getAttribute("userManager");

if (userManager == null || !userManager.isLoggedIn()) {
    ((HttpServletResponse) response).sendRedirect("login.xhtml");
} else {
    chain.doFilter(request, response);
}

将上述过滤器映射到所需的URL模式。
如果仍然希望重新考虑使用容器管理的身份验证,则以下相关答案可能会有用:

感谢您的超快回答。也许不使用应用程序容器中的持久层是不明智的,但当我尝试使用我的表结构/设计时,我偶然发现了Patrol。使用容器领域,它感觉像是一个黑盒子。但是通过ServletFilter,我仍然可以限制所有对根目录和其他文件夹的访问。所以我明天会试一下这个方法。再次感谢。 - Chris

0

如果您正在使用JDBC领域安全,请注意。在Glassfish管理控制台中配置领域的字段中,有一些固定/预期的单词。

JAAS上下文:字段中,您必须键入:jdbcRealm。此关键字使安全容器使用预期的JDBC领域。如果您键入其他内容,则无法正常工作。

这里有一个很好的例子,由Gordan Jugo完成; Netbeans/Glassfish JDBC Security Realm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接