使用 Servlet 3.0 以编程方式控制登录

Posted

技术标签:

【中文标题】使用 Servlet 3.0 以编程方式控制登录【英文标题】:Programmatically control login with Servlet 3.0 【发布时间】:2011-09-05 13:57:21 【问题描述】:

我已经测试了 Glassfish 3.0.1 中的默认安全容器,得出的结论是我不会再花时间在这上面了。相反,我想自己控制验证。但我需要一些指导才能让我走上正轨。

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

我的问题是;

    如果用户未登录(如果访问某些文件夹),我是否需要 ServletFilter 来重定向流量? 用户成功登录后如何存储用户密码?

感谢任何帮助或示例链接,问候克里斯。

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;
    

【问题讨论】:

【参考方案1】:

如果你想使用request.login(),那么你应该已经在容器中配置了一个代表用户数据库的领域。但是您似乎已经用一些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!)

像这样进行身份验证时,您肯定需要filter 来限制访问。使用容器管理的安全性时,您通常会将其指定为 <url-pattern><security-constraint>。但没有它,你必须把它拿在手中。很高兴知道 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 模式。


当您仍想重新考虑使用容器管理的身份验证时,以下相关答案可能会有用:

Java EE Login Page Problem(和Configuring Realm in Glassfish) Performing user authentication in Java EE / JSF using j_security_check

【讨论】:

感谢您的超级快速回答。也许不使用应用容器中的领域是不明智的。但是当我尝试使用我的表格结构/设计时,我偶然发现了巡逻。对容器领域的黑匣子来说,感觉就像是一个黑盒子。但是使用 ServletFilter 我仍然可以限制对根目录和其他文件夹的所有访问。所以我明天试一试。再次感谢。【参考方案2】:

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

JAAS Context: 文件中,您必须输入:jdbcRealm。此关键字使安全容器使用预期的 JDBC 领域。如果您键入其他内容,它将不起作用。

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

【讨论】:

以上是关于使用 Servlet 3.0 以编程方式控制登录的主要内容,如果未能解决你的问题,请参考以下文章

Servlet 3.0 的 MultipartResolver 的 Spring 4 Java 配置

在 servlet 中以编程方式调用过滤器(使用码头/火花创建)?

在 rootView Swift 3.0 之后以编程方式在 ViewControllers 添加栏按钮项

如何以编程方式设置根视图控制器?

Spring Security 3 以编程方式登录

我可以使用 UCMA 3.0 以编程方式建立视频通话吗?