2016-08-08 29 views
0

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

插图:

我的资源

@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客户端打网址

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(); 
+0

请更新您的问题与您如何击中网址。你在卷曲吗?您是否将标题设置为接受JSON作为请求(默认为纯文本)。另外,你的资源并不能说明它的期望值(我认为当你使用jackson时默认为json,但这只是一个假设)。 – pandaadb

+0

尝试添加到您的标题:“Content-Type:application/json” – pandaadb

+0

@pandaadb Content-Type设置为text/plain。但我不认为这是这个问题。这个问题与我认为的InputStream有关。 – amitection

回答

2

您的请求负载不是JSON。这是一个包含JSON编码为Base64的JWT令牌。这是一段文字。因此,请求Content-Typetext/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)注释您的资源方法。

+0

谢谢!你是对的。我的方式很混乱。你的更清洁。将更新我的代码。 – amitection

+0

是的 - 这似乎是正确的。我不知道JwtTokens,并认为这是你的发明:) – pandaadb

+0

@pandaadb对于智威汤逊,请检查https://jwt.io/。 –

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提到的原因,泽西无法将其识别为JSON文件,因此无法将其映射到Person POJO。

+0

如果您要在有效负载中发送JWT,请求的“Content-Type”应该是“text/plain”而不是“application/json”。请参阅我的[answer](http://stackoverflow.com/a/38829866/1426227)以进行澄清。 –