我有一个小过滤器来使用一些非常基本的HMAC方法来验证请求。
只要没有实际的请求有效载荷,一切正常。
现在,当存在非空的有效负载时,身份验证本身仍然有效,但负责该请求的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等)。
我希望你们能给我一个提示......谢谢!
答案 0 :(得分:2)
以前的评论是对的,但使用会更好
ContainerRequest context = (ContainerRequest) containerRequestContext;
context.bufferEntity();
String entity = context.readEntity(String.class);
因为流将被关闭,而jackson将不会从端点上的流中获取实体。 在创建流之前使用jackson ObjectMapper,如果没有这个,你就无法在端点上获取实体简单Stream使用不适用于jackson的本机序列化
requestContext.setEntityStream(new ByteArrayInputStream(new ObjectMapper().writeValueAsBytes(entity)));
答案 1 :(得分: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 :(得分:1)
这里很晚,但是当我遇到相同的问题时,这对我有用:
您只需要从InputStream
类型实体中创建一个String
类型,然后像这样将其写回到您的ContainerRequestContext
-
requestContext.setEntityStream(IOUtils.toInputStream(entity));
就在您的代码下面
String entity = (scanner.hasNext()) ? scanner.next() : "";
IOUtils
来自org.apache.commons.io
。