java - 如何使用 Java EE 安全性从 HttpSessionListener 访问登录主体?

标签 java jakarta-ee

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

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

最佳答案

我使用了自定义的 HttpAuthenticationMechanism,如果有人需要它的话,这里就是它(尽管我很高兴收到一些关于它是否有任何安全缺陷或改进的反馈) .

在实现 HttpAuthenticationMechanism@ApplicationScoped 类中:

@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中:

 @Override
public void sessionDestroyed(HttpSessionEvent se) {
    User user = (User) se.getSession().getAttribute("user");

    if (user != null) {
        // logging
    }
}

关于java - 如何使用 Java EE 安全性从 HttpSessionListener 访问登录主体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56853513/

相关文章:

java - EJB stub 线程安全吗?

java - 无法通过 Java 代码从 XML 文档中删除元素和子元素

java - AWS Java SDK 2 S3复制对象

java - 拦截器和装饰器的区别

jakarta-ee - 使用 Apache iBatis SqlMaps queryForList 进行分页

java - 测试中没有 EntityManager 的持久性提供程序

java - Where Annotation in hibernate with date as 子句

java - 无法使用 next() 前进

java - 如何从 Struts1 中的 url 中删除 '.do' 前缀?

jsp - 如何在Java ee中冒泡异常?