Java EE身份验证:如何捕获登录事件?

Lui*_*ese 7 java authentication java-ee

给定为Java Web应用程序定义的FORM类型的身份验证机制,如何在重定向到请求的资源之前捕获登录执行的事件?是否有任何类型的监听器,我可以在用户登录时将我的代码执行?

我觉得定义过滤器不是最好的解决方案,因为过滤器链接到资源,即使用户已经过身份验证并要求资源,也会调用过滤器.我想知道是否只有登录事件触发了一些类/方法.

Bal*_*usC 7

Java EE中没有这样的事件.然而.作为JSR375的一部分,容器管理的安全性将完全重做,因为它目前分散在不同的容器实现中,并且不是跨容器兼容的.这在Java EE 8 Security API演示文稿中有概述.

已经有一个正在进行的安全API的参考实现,Soteria,由我的同事Arjan Tijms开发.使用新的Security API,CDI将用于触发您可以使用的身份验证事件@Observes.关于规范的讨论发生在这个邮件列表线程中.它尚未在Soteria中具体实施.

在此之前,假设FORM基于用户主体内部存储在会话中的基于身份验证,最好的办法是手动检查servlet过滤器,如果请求中存在用户主体,而HTTP中不存在您登录用户的表示会话.

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
    HttpServletRequest request = (HttpServletRequest) req;
    String username = request.getRemoteUser();

    if (username != null && request.getSession().getAttribute("user") == null) {
        // First-time login. You can do your thing here.
        User user =  yourUserService.find(username);
        request.getSession().setAttribute("user", user);
    }

    chain.doFilter(req, res);
}
Run Code Online (Sandbox Code Playgroud)

请注意,注册过滤器/j_security_check并不能保证工作,因为一个像样的容器会在第一个过滤器被命中之前在内部处理它,这显然是出于安全原因(用户提供的过滤器可能会以不正当的方式操作请求,无论是意外还是意识到) .

如果您碰巧使用Java EE服务器使用Undertow servletcontainer,例如WildFly,那么有一种更干净的方式来挂钩其内部通知事件,然后触发自定义CDI事件.这是在Arjan Tijms的博客中充实的.如博客所示,你最终可以得到一个像这样的CDI bean:

@SessionScoped
public class SessionAuthListener implements Serializable {

    private static final long serialVersionUID = 1L;

    public void onAuthenticated(@Observes AuthenticatedEvent event) {
        String username = event.getUserPrincipal().getName();
        // Do something with name, e.g. audit, 
        // load User instance into session, etc
    }

    public void onLoggedOut(@Observes LoggedOutEvent event) {
        // take some action, e.g. audit, null out User, etc
    }
}
Run Code Online (Sandbox Code Playgroud)