2014-07-23 27 views
2

我有一点过滤器用一些真正基本的HMAC方法验证请求。ContainerRequestFilter导致JAX-RS服务方法中的NPE

只要没有实际的请求有效载荷,一切正常。

现在,当存在非空有效负载时,身份验证本身仍然有效,但负责请求的REST服务将不会收到任何内容。 这里的滤波方法:

public void filter(ContainerRequestContext context) 
      throws IOException { 

     // perform check on responsible service - look for @PermitAll and so on 
     if (isAuthenticationRequired(context) == false) { 
      return; 
     } 


     String callerKey = context.getHeaderString("callerKey"); 

     if (callerKey == null) { 
      context.abortWith(Response. 
        status(Response.Status.UNAUTHORIZED) 
        .build()); 
     } 

     UriInfo uriInfo = context.getUriInfo();    
     String absPath = uriInfo.getAbsolutePath().toString(); 

     String checksum = context.getHeaderString("checksum"); 

     // As this is the only action related to the request's entity (payload) 
     // I already played around with it a while. This is a readonly operation, isn't 
     // it?! The stream must not be closed. 
     InputStream entityStream = context.getEntityStream(); 
     Scanner scanner = new Scanner(entityStream).useDelimiter("\\A"); 
     String entity = (scanner.hasNext()) ? scanner.next() : ""; 

     // Collect parameters for underlying business bean that performs the check. 
     RequestAuthenticationOrder order; 
     order = new RequestAuthenticationOrderBuilder() 
       .absolutePath(absPath) 
       .completeEntity(entity) 
       .checksum(checksum) 
       .callerlKey(callerKey) 
       .build(); 
     try { 
      // basically checks if checksum is correct and if that's true make 
      // corresponding user available to the REST-service 
      context.setProperty("authenticatedUser", 
        identificationService.authenticateRequest(order)); 

     } catch (AuthenticationException aux) { 
      Logger.getLogger(AuthenticationFilter.class.getName()).log(Level.SEVERE, null, aux); 
     } 
    } 

这没有参数服务方法的工作原理:

@Path("/protected") 
public class ProtectedController extends AbstractResourceController { 

    @GET 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response protect() { 
     // callingUser is the result of the previous filtering. It's defined in 
     // superclass AbstractResourceController 
     return Response.accepted(new ProtectedResponse((callingUser != null) 
       ? callingUser.getNickname() 
       : "no user authenticated?")).build(); 
    } 
} 

这一次将不会收到任何东西:

@Path("/logout") 
public class LogoutController extends AbstractResourceController{ 
    @POST @Consumes(MediaType.APPLICATION_JSON) 
    public void logout (LogoutRequest request) { 
     request.getFoo(); // NPE  
    } 
} 

注意的参数是简单JAXB-注释pojos。由于某种原因,这里没有任何得到解决。

一切运行在Wildfly 8上,我使用服务器库(Resteasy,jackson等)。

我希望你们能给我一个提示......谢谢!

回答

1

从ContainerRequestContext获取完整实体所需的inputStream在过滤器中消耗。每个后续组件都不会从流中获取任何内容。

有几种可能的解决方案。我决定引入一个缓冲区:

// ... 
InputStream entityStream = new BufferedInputStream(context.getEntityStream()); 
entityStream.mark(1000); // Hmn, what would be a proper limit...Further investigation 
Scanner scanner = new Scanner(entityStream).useDelimiter("\\A"); 
String entity = (scanner.hasNext()) ? scanner.next() : ""; 
entityStream.reset(); 
context.setEntityStream(entityStream); 
// .... 

我不知道是否有更好的方法来解决这个问题...这一个工程。

2

上的评论是正确的,但使用会更好

ContainerRequest context = (ContainerRequest) containerRequestContext; 
context.bufferEntity(); 
String entity = context.readEntity(String.class); 

因为流将被关闭,杰克逊将不会在端点从流获取实体。 没有这个创建流使用杰克逊ObjectMapper之前不能得到的,在端点简单流使用本机序列化实体,是不是适用于杰克逊

requestContext.setEntityStream(new ByteArrayInputStream(new ObjectMapper().writeValueAsBytes(entity))); 
+0

啊,非常感谢你与这样的老花你的时间题!由于目前我还没有在这方面开展工作,所以我无法测试您的解决方案。所以我不能简单地接受它。希望你没关系!至少赶上! –