操纵ContainerRequestFilter

时间:2016-08-08 10:31:28

标签: java filter jersey jackson dropwizard

我有一个加密字符串由客户端发送。我试图使用 ContainerRequestFilter 然后解密拦截字符串并再次设置InputStream,以便 Jackson 可以使用它来映射到POJO。

插图:

我的资源

@Path("auth")
public class AuthResource {

@POST
public Response testResource(@Auth AuthUser auth, Person person) {

    System.out.println("Recieved Resource:: "+ new Gson().toJson(person));

    return null;
    }
}

Person.java

public class Person {

    private String name;
    private int age;

    public Person() {};

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

我的过滤器

@Provider
public class MyFilter implements ContainerRequestFilter {

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException {

        InputStream inputStream = requestContext.getEntityStream();

        StringWriter writer = new StringWriter();
        IOUtils.copy(inputStream, writer, "UTF-8");
        String theString = writer.toString();

        String decryptedMessage = "";
        try {
            decryptedMessage = JwtToken.decryptPayload(theString);
            System.err.println("Decrypted Message: "+decryptedMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }

        InputStream stream = new ByteArrayInputStream(decryptedMessage.getBytes(StandardCharsets.UTF_8));
        requestContext.setEntityStream(stream);
    }

}

据我所知,一旦使用了InputStream,它就无法再次使用。但是使用 requestContext.setEntityStream(stream); 我试图再次设置InputStream以供Jackson使用。

尽管如此,我仍然无法在我的资源中获取此对象。解密工作正常,因为我使用调试器进行了测试。

我收到以下错误: 415:不支持的媒体类型

编辑1:我正在使用Adavanced Rest Client来点击网址

http://localhost:8080/auth

标题

authorization: Basic ZXlKaGRYUm9iM0pwZW1GMGFXOXVJam9pWVcxcGRDSXNJbUZzWnlJNklraFRNalUySW4wLmUzMC5MLUtmOUxQNjFSQ21Bektob2lTR0V4bEJ3RXRUMXhrR3A3bUpIZmFSeV9FOnBhc3M=

原始有效负载:

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g

只需使用JWT加密有效负载:

Jwts.builder().setPayload(new Gson().toJson(new  Person("Amit",22))).signWith(SignatureAlgorithm.HS256, key).compact();

2 个答案:

答案 0 :(得分:2)

您的请求有效负载不是JSON。它是一个JWT令牌,包含一个编码为Base64的JSON。这是一段文字。因此,请求的Content-Type应该是text/plain而不是application/json

POST /api/auth HTTP/1.1
Host: example.org
Content-Type: text/plain

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g

您的过滤器修改请求的有效负载:过滤器从请求有效负载获取JWT令牌,获取令牌有效负载,将令牌有效负载解码为JSON字符串并将JSON字符串设置为请求有效负载。

执行过滤器后,请求将包含一个JSON字符串,而不仅仅是一段文本。因此,在此之后,请求的Content-Type应修改为application/json。可以通过以下方式实现:

requestContext.getHeaders().remove(HttpHeaders.CONTENT_TYPE);
requestContext.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);

要确保在资源匹配之前执行过滤器,请使用@PreMatching为过滤器添加注释。

请勿忘记使用@Consumes(MediaType.APPLICATION_JSON)注释您的资源方法。

答案 1 :(得分:0)

我尝试将有效负载更改为JSON文档:

"temp":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g"

并使用我的过滤器中的以下代码提取加密的有效负载:

JsonObject jsonObject = new Gson().fromJson(theString, JsonObject.class);
        theString = jsonObject.get("temp").getAsString();

还将资源更改为 @Consumes(MediaType.APPLICATION_JSON)

它有效!

我想原因如pandaadb所述,Jersey无法将其识别为JSON文档,因此无法将其映射到Person POJO。