【问题标题】:Hibernate Envers : How to inject SecurityContext (REST) in RevisionListener?Hibernate Envers:如何在 RevisionListener 中注入 SecurityContext (REST)?
【发布时间】:2021-10-09 15:47:28
【问题描述】:

我有一个 REST API(使用带有 microprofile-jwt 的 wildfly 20),所以我想使用 Hibernate Envers 审核更改。不幸的是,我无法获取我的 Principal 对象:javax.ws.rs.core.SecurityContext 为空。

所以我的问题是:如何在我的 RevisionListener 中注入 SecurityContext 并获取 Principal ?

import java.security.Principal;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

import org.hibernate.envers.RevisionListener;

public class CustomRevisionListener implements RevisionListener {

    @Context
    private SecurityContext context;

    @Override
    public void newRevision(Object o) {
        CustomRevEntity e = (CustomRevEntity) o;
        e.setLogin(getUser());
    }

    private String getUser() {
        if(context == null) return "anonymous no context";
        Principal principal = context.getUserPrincipal();
        return principal == null ? "anonymous" : principal.getName();
    }
}

【问题讨论】:

    标签: rest hibernate-envers java-ee-8 microprofile security-context


    【解决方案1】:

    这是行不通的,因为 bean 的创建是在容器之外完成的。如果您想使用 envers,则需要一种方法将原理从容器管理的 bean 传递到由 envers-extension 创建和管理的 RevisionListener-bean。

    一种方法是使用 public static ThreadLocal threadlocalPrincipal = new ThreadLocal();

    在使用 JPA 或 Hibernate 的 bean 中,@Context SecurityContext 上下文应该可以工作。在调用任何 Dao 或任何其他 Hibernate-Using 方法之前,使用 threadlocalPrincipal.set(...) 填充公共静态变量。在监听器内部使用 threadlocalPrincipal.get() 来访问当前线程中设置的当前变量。

    确保之后在 finally 块中使用 threadLocalPrincipal.remove() 清除 Threadlocal 变量,以避免内存泄漏。

    【讨论】:

      【解决方案2】:

      我收到了来自hibernate论坛的答案:https://discourse.hibernate.org/t/how-to-get-username-envers-api-rest/5592

      为了能够将 SecurityContext 注入 RevisionListner(使用@Inject),您需要这个过滤器:

      @Provider
      public class SecurityRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {
      
          private static final ThreadLocal<SecurityContext> THREAD_LOCAL = new ThreadLocal<>();
      
          @RequestScoped
          @Produces
          public SecurityContext getSecurityContext() {
              return THREAD_LOCAL.get();
          }
      
          @Override
          public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
                  throws IOException {
              THREAD_LOCAL.remove();
          }
      
          @Override
          public void filter(ContainerRequestContext requestContext) throws IOException {
              THREAD_LOCAL.set(requestContext.getSecurityContext());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-21
        • 1970-01-01
        • 2013-12-21
        • 2020-01-14
        • 2018-08-18
        • 2017-10-25
        • 1970-01-01
        • 2015-08-16
        相关资源
        最近更新 更多