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 相同的主体。
我有类似下面的设置。这是一个简化版本,但我认为它传达了基本思想。我正在使用 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 相同的主体。