MockMVC - Как проверить содержимое токена JWT в весеннем тесте интеграции безопасности с org.hamcrest.Matcher - PullRequest
0 голосов
/ 03 декабря 2018

Я получаю токены JWT в ответ на запрос MockMvc.Я хочу проверить содержание этого ответа:

mockMvc.perform(post("/authorize")
        .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeEmailAndPassword("test1@app.com", "1111"))
        .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        .params(params)
        .accept(MediaType.APPLICATION_JSON))
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
    .andDo(print())
    .andExpect(status().isOk())
;

Результат будет:

{
    "id_token": "............(long Base64 string)"
}

Когда мы декодируем токен с помощью JWT.io, мы видим это:

{
  "sub": "cc15a160-2d62-4091-b89a-117e77346a58",
  "nbf": 1543846725,
  "auth_level": "trusted",
  "iss": "http://localhost:9090/",
  "exp": 1543847724,
  "iat": 1543846725,
  "nonce": "random_string",
  "jti": "64b8b6e3-5cd0-4242-bcea-2c5d498d64c1"
}

Все хорошо, но я хочу сделать что-то вроде:

.andExpect(jsonPath("$.id_token", Matchers.not(null)))
.andExpect(decodeJWT(jsonPath("$.id_token")).getValueOf("nonce"), Matchers.is("random_string"));

Как я могу это сделать?

1 Ответ

0 голосов
/ 03 декабря 2018

Ну, я нахожу ответ сам ... В принципе, с org.hamcrest.Matcher невозможно, но мы можем разделить ответ на части и сопоставить их с DTO.

Во-первых, я делаю некоторый статус и основныепроверьте, а затем верните ответ как MvcResult:

MvcResult result = mockMvc.perform(post("/authorize")
                .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeEmailAndPassword("test1@app.com", "1111"))
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(content)
                .accept(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id_token", Matchers.notNullValue()))
            .andReturn();

Затем я создаю несколько DTO для десериализации Джексона: (не забудьте создать класс , а не как внутренний класс, потому что Джексон будетжалуются на то, что «можно использовать только конструктор без аргументов внутреннего нестатического класса»)

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
class TokenResponseDTO implements Serializable {
    //@JsonProperty("id_token")
    private String idToken;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
class JWTPayloadDTO implements Serializable {
    private String aud;
    private String sub;
    private String nbf;
    private String authLevel;
    private String iss;
    private Long exp;
    private Long iat;
    private String nonce;
    private String jti;
}

Наконец, разбор токена JWT намного проще, чем я думал:

String token = mapper.readValue(result.getResponse().getContentAsString(), TokenResponseDTO.class).getIdToken();
JWSObject jwsObject = JWSObject.parse(token);
JWTPayloadDTO payload = mapper.readValue(jwsObject.getPayload().toString(), JWTPayloadDTO.class);

Assert.assertEquals("random_string", payload.getNonce());
... // other checks
...