JSF中的基于表单的身份验证

4
我希望在JSF/Primefaces应用程序中实现简单的身份验证。我尝试了很多不同的方法,例如对话框 - 登录演示在对话框上进行简单的测试,但它没有登录用户。
我还查看了Java安全性,例如:
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected Area</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>REGISTERED_USER</role-name>
    </auth-constraint>
</security-constraint>

使用这个方法可以保护/protected目录下的所有内容,但据我了解,需要在服务器上定义一个领域来进行身份验证。我不想在服务器上指定它,只想在数据库中进行简单的查找。

有没有一种方法可以在不在应用程序服务器中定义任何内容的情况下对用户进行身份验证?或者其他简单的解决方案来验证和保护不同的页面?

2个回答

7
有没有一种方法可以在不在应用服务器中定义任何内容的情况下对用户进行身份验证?
这是一个漫长而非常棘手的问题。它经常被提出作为批评Java EE的主要观点之一。
故事的核心是,传统上,Java EE应用程序应该部署具有“未解决的依赖项”。这些依赖项必须在应用服务器上得到满足,通常由不是开发人员的人完成,通常使用某种GUI或控制台。
安全配置就是其中之一未解决的依赖关系。
如果在应用服务器上完成安全配置,则按定义始终不可移植,例如必须以应用服务器特定的方式完成。这完全排除了使用应用程序域模型(例如JPA实体User)进行身份验证的可能性。
一些服务器(例如JBoss AS)允许从应用程序内部配置其专有的安全机制,并且还允许从应用程序中加载“自定义登录模块”(术语对于几乎每个服务器都不同)。通过一些小的修改,这将允许使用应用程序域模型和应用程序本身用于身份验证的相同数据源。

最近出现了一个相对较为不知名的便携式身份验证方式,可在应用程序中完成。这是通过JASPIC SPI实现的,也称为JASPIJSR 196。基本上,这个JASPIC似乎就是你正在寻找的。

不幸的是,JASPIC并非完美无缺,尽管它是Java EE 6的技术,而我们现在已经接近于Java EE 7,但目前各种应用服务器对JASPIC的支持仍然不稳定。除此之外,尽管JASPIC已经标准化,但应用服务器供应商们仍需要专有配置才能使其正常工作。

我写了一篇关于JASPIC的文章,更详细地解释了当前存在的问题: 使用JASPIC在Java EE中实现容器身份验证


听起来有点奇怪。如果我在应用服务器中进行身份验证,它就不再具有可移植性了。如果我使用另一个应用服务器,我必须迁移整个用户库或重新实现它。我会看一下JASPIC,也许这可以帮助我,谢谢。 - Mike Petersen
@MikePetersen 的确如此,但这是传统方法的想法。它以应用服务器为中心而不是以应用程序为中心。其想法是在单个应用服务器上运行多个应用程序,并且它们都使用相同的身份验证。因此,它在应用服务器上设置。当然,如果您只运行具有自己身份验证的单个应用程序,则没有意义。因此,这取决于情况。一种方法并不比另一种更好,只是有不同的用例。 - Arjan Tijms
如果您有更多使用相同用户基础的应用程序,那么您是正确的,这是有意义的。我认为不同的应用程序具有不同的身份验证对于Web应用程序来说更为常见。 - Mike Petersen

0

我已经找到了一个适合我的简单解决方案,只需使用Web过滤器即可。我已经在web.xml中添加了一个过滤器,如下所示:

<!-- Authentication Filter -->
<filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>org.example.filters.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/protected/*</url-pattern>
</filter-mapping>

过滤器看起来像这样

@WebFilter(filterName="AuthenticationFilter")
public class AuthenticationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        Cookie[] cookies = ((HttpServletRequest)request).getCookies();

        // Try to find a valid session cookie
        if (cookies != null) {
            String sessionId = null;
            for (Cookie cookie : cookies) {
                if ("sessionId".equals(cookie.getName())) {
                        sessionId = cookie.getValue();
                }
            }

            // Check if we have a valid session
            UserSession session = Backend.getInstance().getSessionGateway().getBySessionId(sessionId);

            if (session != null) {
                chain.doFilter(request, response);
                return;
            } else if (sessionId != null) {
                // Remove the cookie
                Cookie cookie = new Cookie("sessionId", null);
                cookie.setMaxAge(-1);
                ((HttpServletResponse)response).addCookie(cookie);
            }
        }


//      Problem due to relative path!!
//      ((HttpServletResponse)response).sendRedirect("../login.xhtml");
        RequestDispatcher rd = request.getRequestDispatcher("/login.xhtml");
        rd.forward(request, response);
    }
}

所以我只需要实现一个Bean来进行身份验证并设置会话cookie。我将添加用户代理以获得额外的安全性,但基本上它可以工作。

我唯一的问题是无法重定向,因为它没有使用上下文路径,而是直接重定向到/index.xhtml,而不是/my_app_context/index.xhtml。


1
为什么你要通过自定义 Cookie 来重新发明 HttpSession - BalusC

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