在 JAX-RS 资源中组合 @Context 和 @RolesAllowed?
Combining @Context and @RolesAllowed in a JAX-RS resource?
是否可以在 Apache CXF 2.4.6 和 Spring Security 3.2.8 的 JAX-RS 资源中使用 Context annotation and RolesAllowed 注释?
我的 CXF 配置:
<jaxrs:server address="/example">
<jaxrs:serviceBeans>
<ref bean="myResourceImpl"/>
</jaxrs:serviceBeans>
</jaxrs:server>
我的Java源代码:
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get();
}
@Named
public class MyResourceImpl implements MyResource {
@Context
private SecurityContext securityContext;
@Override
@RolesAllowed("ROLE_user")
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
启动服务器后,出现以下异常:
Caused by: java.lang.IllegalArgumentException: Can not set javax.ws.rs.core.SecurityContext field MyResourceImpl.securityContext to com.sun.proxy.$Proxy473
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:741)
at org.apache.cxf.jaxrs.utils.InjectionUtils.run(InjectionUtils.java:164)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.cxf.jaxrs.utils.InjectionUtils.injectFieldValue(InjectionUtils.java:160)
at org.apache.cxf.jaxrs.utils.InjectionUtils.injectContextProxiesAndApplication(InjectionUtils.java:912)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.injectContexts(JAXRSServerFactoryBean.java:354)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.updateClassResourceProviders(JAXRSServerFactoryBean.java:380)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:145)
... 59 more
如果我删除两个注释之一,它就可以正常工作。
问题似乎是 Spring 创建了一个 proxy and Apache CXF cannot inject that proxy with the SecurityContext。
我必须使用 Spring 安全性,不能使用 container-based security。
我找到了四个解决方法:
扩展接口
@Path("/myresource")
public interface MyResource {
@Context
public void setSecurityContext(Security securityContext);
@GET
@Produces(MediaType.TEXT_XML)
String get();
}
@Named
public class MyResourceImpl implements MyResource {
private SecurityContext securityContext;
@Override
public void setSecurityContext(Security securityContext) {
this.securityContext = securityContext
}
@Override
@RolesAllowed("ROLE_user")
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
但是这个解决方案并不完美,因为我的client应该看不到实现细节。
-
如果我为 SecurityContext
添加第二个带有 public setter 的接口,Apache CXF 可以用 SecurityContext
.[=22 注入 JDK proxy =]
public interface ContextAware {
@Context
public void setSecurityContext(Security securityContext);
}
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get();
}
@Named
public class MyResourceImpl implements MyResource, ContextAware {
private SecurityContext securityContext;
@Override
public void setSecurityContext(Security securityContext) {
this.securityContext = securityContext
}
@Override
@RolesAllowed("ROLE_user")
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
-
如果我删除接口 Spring 使用 CGLIB 代理。
@Named
@Path("/myresource")
public class MyResourceImpl {
@Context
private SecurityContext securityContext;
@RolesAllowed("ROLE_superadmin")
@GET
@Produces(MediaType.TEXT_XML)
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
但是这个方案不好,因为我的client应该看不到实现细节。而且我的客户不需要实现依赖项。
-
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get();
}
@Named
public class MyResourceImpl implements MyResource {
@Context
private SecurityContext securityContext;
@Override
@RolesAllowed("ROLE_user")
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
我对@dur 的解决方案稍作改动。我没有将 @Context
作为字段,而是将其作为参数传递给我需要它的方法(我使用的是 SearchContext
):
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get(@Context SecurityContext securityContext);
}
@Named
public class MyResourceImpl implements MyResource {
@Override
@RolesAllowed("ROLE_user")
public String get(SecurityContext securityContext) {
return securityContext.getUserPrincipal().getName();
}
}
是否可以在 Apache CXF 2.4.6 和 Spring Security 3.2.8 的 JAX-RS 资源中使用 Context annotation and RolesAllowed 注释?
我的 CXF 配置:
<jaxrs:server address="/example">
<jaxrs:serviceBeans>
<ref bean="myResourceImpl"/>
</jaxrs:serviceBeans>
</jaxrs:server>
我的Java源代码:
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get();
}
@Named
public class MyResourceImpl implements MyResource {
@Context
private SecurityContext securityContext;
@Override
@RolesAllowed("ROLE_user")
public String get() {
return securityContext.getUserPrincipal().getName();
}
}
启动服务器后,出现以下异常:
Caused by: java.lang.IllegalArgumentException: Can not set javax.ws.rs.core.SecurityContext field MyResourceImpl.securityContext to com.sun.proxy.$Proxy473
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:741)
at org.apache.cxf.jaxrs.utils.InjectionUtils.run(InjectionUtils.java:164)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.cxf.jaxrs.utils.InjectionUtils.injectFieldValue(InjectionUtils.java:160)
at org.apache.cxf.jaxrs.utils.InjectionUtils.injectContextProxiesAndApplication(InjectionUtils.java:912)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.injectContexts(JAXRSServerFactoryBean.java:354)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.updateClassResourceProviders(JAXRSServerFactoryBean.java:380)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:145)
... 59 more
如果我删除两个注释之一,它就可以正常工作。
问题似乎是 Spring 创建了一个 proxy and Apache CXF cannot inject that proxy with the SecurityContext。
我必须使用 Spring 安全性,不能使用 container-based security。
我找到了四个解决方法:
扩展接口
@Path("/myresource") public interface MyResource { @Context public void setSecurityContext(Security securityContext); @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource { private SecurityContext securityContext; @Override public void setSecurityContext(Security securityContext) { this.securityContext = securityContext } @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } }
但是这个解决方案并不完美,因为我的client应该看不到实现细节。
-
如果我为
SecurityContext
添加第二个带有 public setter 的接口,Apache CXF 可以用SecurityContext
.[=22 注入 JDK proxy =]public interface ContextAware { @Context public void setSecurityContext(Security securityContext); } @Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource, ContextAware { private SecurityContext securityContext; @Override public void setSecurityContext(Security securityContext) { this.securityContext = securityContext } @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } }
-
如果我删除接口 Spring 使用 CGLIB 代理。
@Named @Path("/myresource") public class MyResourceImpl { @Context private SecurityContext securityContext; @RolesAllowed("ROLE_superadmin") @GET @Produces(MediaType.TEXT_XML) public String get() { return securityContext.getUserPrincipal().getName(); } }
但是这个方案不好,因为我的client应该看不到实现细节。而且我的客户不需要实现依赖项。
-
@Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource { @Context private SecurityContext securityContext; @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } }
我对@dur 的解决方案稍作改动。我没有将 @Context
作为字段,而是将其作为参数传递给我需要它的方法(我使用的是 SearchContext
):
@Path("/myresource")
public interface MyResource {
@GET
@Produces(MediaType.TEXT_XML)
String get(@Context SecurityContext securityContext);
}
@Named
public class MyResourceImpl implements MyResource {
@Override
@RolesAllowed("ROLE_user")
public String get(SecurityContext securityContext) {
return securityContext.getUserPrincipal().getName();
}
}