我有一个Jersey REST API并使用ContainerRequestFilter
来处理授权。我还在所有端点上使用@ManagedAsync
,以便我的API可以处理数千个并发请求。
我的授权过滤器命中远程服务,但是当运行过滤器时,Jersey还没有将当前线程添加到它的内部ExecutorService
,所以我完全失去了异步的好处。
我可以告诉Jersey我希望这个ContainerRequestFilter
是异步的吗?
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
@Inject
private AuthorizationService authSvc;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// HITS A REMOTE SERVER
AuthorizationResponse authResponse = authSvc.authorize(authToken);
if (!authResponse.isAuthorized())
{
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("unauthorized!")
.build());
}
}
}
这是一个示例资源:
@Path("/stuff")
@Produces(MediaType.APPLICATION_JSON)
public class StuffResource
{
@GET
@Path("/{id}")
@ManagedAsync
public void getById(@PathParam("id") long id, @Suspended final AsyncResponse ar)
{
Stuff s;
// HIT THE DATABASE FOR STUFF
ar.resume(s);
}
}
更新刚刚从泽西岛球员那里听到,从2.7开始这是不可能的。仅异步调用资源方法本身,而不是过滤器。任何有关进行的建议仍然欢迎。
答案 0 :(得分:4)
自2.7以来,这并不是内置于泽西岛。
如果你有任何过滤器或拦截器做任何认真的工作(如点击远程授权服务), @ManagedAsync
是没用的。他们可能会在将来添加异步运行过滤器的功能,但现在你可以自己动手了。
更新 - 还有其他方法......
经过漫长而危险的旅程,我发现了一个非常讨厌的解决方案,我在短期内使用它。以下是我尝试过的内容及其失败/工作原因的概述。Guice AOP - 失败
我使用Guice进行DI(使用Guice注入与Jersey一起工作是feat in itself!),所以我想我可以使用Guice AOP来解决这个问题。虽然Guice注入工作,但是不可能让Guice用Jersey 2创建资源类,因此Guice AOP无法使用资源类方法。如果你拼命想让Guice用Jersey 2创建资源类,那么不要浪费你的时间,因为它不会起作用。这是well-known problem。
HK2 AOP - 推荐解决方案
HK2刚刚发布了AOP功能,请参阅this question了解如何使其正常运行。
监控 - 也有效
这不适合胆小的人,Jersey docs完全不鼓励。您可以注册ApplicationEventListener
并覆盖onRequest
以返回侦听RequestEventListener
的{{1}}并调用身份验证/授权服务。此事件由RESOURCE_METHOD_START
线程触发,这是此处的整个目标。有一点需要注意,@ManagedAsync
方法是无操作方法,所以这不会像普通的abortWith
那样有效。相反,如果auth失败则可以抛出异常,并注册ContainerRequestFilter
来处理异常。如果有人大胆尝试一下,请告诉我,我会发布代码。
答案 1 :(得分:1)
我不确定这是不是你想要的,但是,你看过Spring的OncePerRequestFilter
吗?我目前正在将其用于我的授权层,其中每个请求都会通过一些扩展此OncePerRequestFilter
的过滤器,具体取决于我的过滤器如何映射到URL。以下是我如何使用它的快速概述:
Authentication/Authorization of a resource in Dropwizard
我对这些过滤器的异步调度部分不是很清楚,但我希望这个链接至少可以解释你想要实现的目标!
答案 2 :(得分:0)
我们使用Spring安全性进行身份验证/授权。我使用具有空路径的子资源定位器解决了这个问题,如下所示:
@Path("/customers")
public class CustomerResource {
@Inject
private CustomerService customerService;
@Path("")
public CustomerSubResource delegate() {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return new CustomerSubResource(auth);
}
public class CustomerSubResource {
private final Authentication auth;
public CustomerSubResource(final Authentication auth) {
this.auth = auth;
}
@POST
@Path("")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ManagedAsync
public void createCustomer(final Customer customer, @Suspended final AsyncResponse response) {
// Stash the Spring security context into the Jersey-managed thread
SecurityContextHolder.getContext().setAuthentication(this.auth);
// Invoke service method requiring pre-authorization
final Customer newCustomer = customerService.createCustomer(customer);
// Resume the response
response.resume(newCustomer);
}
}
}