2016-08-08 31 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)以進行澄清。 –