2014-07-23 53 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

啊,非常感謝你與這樣的老花你的時間題!由於目前我還沒有在這方面開展工作,所以我無法測試您的解決方案。所以我不能簡單地接受它。希望你沒關係!至少趕上! –