Java EE 身份验证:如何捕获登录事件? [英] Java EE authentication: how to capture login event?

查看:24
本文介绍了Java EE 身份验证:如何捕获登录事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Given an authentication mechanism of type FORM defined for a Java web app, how do you capture the login performed event before being redirected to requested resource? Is there any kind of listener where I can put my code to be executed when a user logs in?

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

I feel like defining a filter is not the best solution, as the filter is linked to the resource and would be invoked even when the user is already authenticated and asking for a resource. I'm wondering if there's some class/method triggered only by login event.

推荐答案

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

There's no such event in Java EE. Yet. As part of JSR375, container managed security will be totally reworked as it's currently scattered across different container implemantations and is not cross-container compatible. This is outlined in this Java EE 8 Security API presentation.

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

There's already a reference implementation of Security API in progress, Soteria, developed by among others my fellow Arjan Tijms. With the new Security API, CDI will be used to fire authentication events which you can just @Observes. Discussion on the specification took place in this mailing list thread. It's not yet concretely implemented in Soteria.

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

Until then, assuming FORM based authentication whereby the user principal is internally stored in the session, your best bet is manually checking in a servlet filter if there's an user principal present in the request while your representation of the logged-in user is absent in the HTTP session.

@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);
}

请注意,在 /j_security_check 上注册过滤器并不能保证工作,因为一个体面的容器会在第一个过滤器被命中之前在内部处理它,出于明显的安全原因(用户提供的过滤器可以操纵以错误的方式请求,无论是无意中还是有意).

Do note that registering a filter on /j_security_check is not guaranteed to work as a decent container will handle it internally before the first filters are hit, for obvious security reasons (user-provided filters could manipulate the request in a bad way, either accidentally or awarely).

如果您碰巧使用 Java EE 服务器,请使用 Undertow servletcontainer,例如 WildFly,然后有一种更简洁的方法来挂钩其内部通知事件,然后触发自定义 CDI 事件.这在 Arjan Tijms 的这篇博客中有详细说明.如博客中所示,您最终可以得到这样的 CDI bean:

If you however happen to use a Java EE server uses the Undertow servletcontainer, such as WildFly, then there's a more clean way to hook on its internal notification events and then fire custom CDI events. This is fleshed out in this blog of Arjan Tijms. As shown in the blog, you can ultimately end up with a CDI bean like this:

@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
    }
}

这篇关于Java EE 身份验证:如何捕获登录事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆