Hibernate Envers:如何在 RevisionListener 中注入 SecurityContext (REST)?

问题描述 投票:0回答:3

我有一个 REST API(使用带有 microprofile-jwt 的 wildfly 20),因此我想使用 Hibernate Envers 审核更改。不幸的是,我无法获取我的主要对象:

javax.ws.rs.core.SecurityContext
为空。

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

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
3个回答
0
投票

这是行不通的,因为 bean 的创建是在容器外部完成的。如果您想使用 envers,则需要一种方法将容器管理的 bean 的原理传达给 envers 扩展创建和管理的 RevisionListener-bean。

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

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

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


0
投票

我从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());
    }
}

0
投票

此解决方案适用于 Quarkus 3.6.5+ 吗?对我来说,SecurityContext 在这些版本中返回 null。仅在 Quarkus 3.6.4 或更低版本 中才有效。

© www.soinside.com 2019 - 2024. All rights reserved.