如何使用Java EE Security从HttpSessionListener访问登录的主体?

时间:2019-07-02 13:23:34

标签: java java-ee java-ee-8

我有一个带有@CustomFormAuthenticationMechanismDefinition的应用程序,我想在登录和注销时都记录用户名,会话ID,IP地址等。与此批注一起应用的HttpAuthMechanism将给定的会话与主体相关联,我可以通过SecurityContext访问该主体。使用直接注销,日志记录没有问题,但是我也想在会话超时时进行日志记录。因此,我创建了一个HttpSessionListener,并在其sessionDestroyed()方法中尝试通过SecurityContext访问登录的用户,但是它返回一个空集,这可能是因为securityContext已经失效了。

我想到的一个解决方案是将用户主体存储在会话参数中(很可能在HttpAuthMechanism实现中发生)并从HttpSessionEvent对象那里访问它,但这并没有感觉不是最干净的解决方案。我可以使用其他监听器还是其他解决方案?

2 个答案:

答案 0 :(得分:0)

我使用了自定义的HttpAuthenticationMechanism,这是任何人都需要的(尽管我很高兴收到有关它是否存在任何安全缺陷或改进的反馈)

在实现@ApplicationScoped的{​​{1}}类中:

HttpAuthenticationMechanism

在已实现的@Override public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException { if (!httpMessageContext.isProtected()) { return httpMessageContext.doNothing(); } HttpSession session = request.getSession(false); Credential credential = httpMessageContext.getAuthParameters().getCredential(); // If we already have a session, we get the user from it, unless it's a new login if (session != null && !(credential instanceof UsernamePasswordCredential)) { User user = (User) session.getAttribute("user"); if (user != null) { return httpMessageContext.notifyContainerAboutLogin(user, user.getRoles()); } } // If we either don't have a session or it has no user attribute, we redirect/forward to login page if (!(credential instanceof UsernamePasswordCredential)) { return redirect(request, response, httpMessageContext); } // Here we have a Credential, so we validate it with the registered IdentityStoreHandler (injected as idStoreHandler) CredentialValidationResult validate = idStoreHandler.validate(credential); Context context = new Context(); context.setIp(request.getRemoteAddr()); if (validate.getStatus() == CredentialValidationResult.Status.VALID) { session = request.getSession(true); CallerPrincipal callerPrincipal = validate.getCallerPrincipal(); session.setAttribute("user", callerPrincipal); context.setUser(callerPrincipal); context.setSessionId(session.getId()); Logger log = new Logger(logger, "validateRequest", context); log.debug("Logged in user: " + callerPrincipal.getName()); String redirectPage = "whatYouWant.xhtml"; redirect(request, response, httpMessageContext, redirectPage); return httpMessageContext.notifyContainerAboutLogin(validate); } else if (validate.getStatus() == CredentialValidationResult.Status.NOT_VALIDATED) { return redirect(request, response, httpMessageContext); } else { // Logging return httpMessageContext.responseUnauthorized(); } } 中:

HttpSessionListener

答案 1 :(得分:0)

您不需要自定义实施HttpAuthenticationMechanism。您可以使用HttpServletRequest.login()进行手动登录(不使用j_security_check操作自动使用容器登录)

LoginServlet

public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String userName = req.getParameter("userName");
        String password = req.getParameter("password");

        if (userName == null) throw new IllegalArgumentException("userName is required.");
        if (password == null) throw new IllegalArgumentException("password is required.");

        try {

            // INVOKE login manually. NOT using j_security_check

            // Alternative: Use JavaEE8 Security API - SecurityContext.authenticate()

            req.login(userName, password);

            if (req.getUserPrincipal() != null) {
                // LOGIN Successfully

                Context context = createContextFrom(req, req.getSession());
                logContext(context);

                req.getSession().setAttribute("loginContext", context);
            }
        } catch (Exception ex) {
            // ...
        }
    }
}

//会话破坏事件

@WebListener
public class SessionListenerImpl implements HttpSessionListener {

    @Override
    public void sessionDestroyed(HttpSessionEvent hse) {
        Context loginContext = hse.getSession().getAttribute("loginContext");

        if (loginContext != null) {
            // Do whatever with loginContext
        }
    }
}