1

I have a REST API (using wildfly 20 with microprofile-jwt) so I would like to audit changes with Hibernate Envers. Unfortunately I can't get my Principal object : the javax.ws.rs.core.SecurityContext is null.

So my question is : how can I inject the SecurityContext in my RevisionListener and get the 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();
    }
}
4

2 回答 2

0

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

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

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

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

于 2021-08-22T20:05:33.653 回答
0

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

为了能够将 SecurityContext 注入 RevisionListner (with @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());
    }
}
于 2021-08-23T07:15:27.903 回答