JAX-RS 使用的无状态 EJB 中的 @Context 注入

@Context injection in Stateless EJB used by JAX-RS

我有类似下面的设置。这是一个简化版本,但我认为它传达了基本思想。我正在使用 Jersey 2.16、Java 1.8 和 Glassfish Open Source 4.1

public interface IReportService {
    String addNewReport(Report report);
}

@Path("reports")
public class ReportResource implements IReportService {
    /**
    * Service layer.
    */
    @EJB
    private transient ReportService service;

    @POST
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    @Produces(MediaType.TEXT_PLAIN)
    @Override
    public String addNewReport(final Report report) {
       return service.addNewReport(report);
    }
}

@Stateless
@LocalBean
public class ReportService implements IReportService {

   @EJB
   private IReportPersistence reportPersistence;

   @Context
   SecurityContext secContext;

   public String addNewReport(final Report report) {
       report.setUserName(secContext.getUserPrincipal().getName());
       reportPersistence.persist(report);
    }
}

但是当我部署并尝试访问 Web 服务时,我从安全上下文中得到一个 NullPointer 异常。似乎根本没有注入上下文。我检查了一下,它是 secContext 变量本身,而不仅仅是来自 getUserPrincipal() 的 return 为空。 Glassfish 日志中除了我的 NullPointer 之外没有警告或异常(这导致 500 错误 returned 到 Web 客户端)。

问题是您在错误的地方使用了 SecurityContext。您必须在 REST 资源 class.

中使用它

您可以尝试以下方法:

@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces(MediaType.TEXT_PLAIN)
@Override
public String addNewReport(final Report report, @Context SecurityContext sc) {
   report.setUserName(sC.getUserPrincipal().getName());
   return service.addNewReport(report);
}

有关详细信息,请查看 Jersey Documentation - Chapter 16. Security

在 EJB 内部,您必须使用 EJBContext (or the SessionContext)。

谢谢,正如 unwichtich 所指出的,我已经使用 EJB 中的 EJBContext 解决了问题。

总而言之,SecurityContext 仅适用于 JAX-RS bean,我已将 SecurityContext 的 EJBContext 对象用于其他 java bean。 您也可以使用 SessionContext 对象,但 EJBContext 接口类似于 SecurityContext 接口。这是一个用法示例:

@DeclareRoles({"administrator","operator","user"})
@PermitAll
@Stateless
public class myFacade {

    @PersistenceContext(unitName = "myPersistencePU")
    private EntityManager em;

    @Resource EJBContext securityContext;

    public DataStuff find(Object id) {
        //Now the securityContext is != null :-D
        String username = securityContext.getCallerPrincipal().getName();
        if(username.equals("gino"){
            return null;
        }
        return getEntityManager().find(entityClass, id);
    }
}

它按预期工作 auto-magically,EJB 看到与 JAX-RS servlet 相同的主体。