MockMVC - 如何使用 org.hamcrest.Matcher 在春季安全集成测试中检查 JWT 令牌的内容

Posted

技术标签:

【中文标题】MockMVC - 如何使用 org.hamcrest.Matcher 在春季安全集成测试中检查 JWT 令牌的内容【英文标题】:MockMVC - How to check the content of a JWT token in a spring security integration test with org.hamcrest.Matcher 【发布时间】:2019-05-04 20:50:08 【问题描述】:

我会从 MockMvc 请求中获取 JWT 令牌作为响应。我想检查一下这个回复的内容:

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】:

好吧,我自己找到了答案...基本上,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();

然后,我为 Jackson 反序列化创建了一些 DTO:(记得创建类 not 作为内部类,因为 Jackson 会抱怨“只能使用内部非静态类的无参数构造函数")

@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

【讨论】:

谢谢。你的回答对我很有帮助。

以上是关于MockMVC - 如何使用 org.hamcrest.Matcher 在春季安全集成测试中检查 JWT 令牌的内容的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MockMvc 测试弹簧控制器方法?

如何使用 mockMvc 检查响应正文中的 JSON

Spring - 如何正确使用@Autowired 来防止控制器/ MockMvc 为空?

如何使用 mockMvc 检查响应正文中的字符串

使用mockmvc测试如何处理无序数组

如何使用mockMvc检查响应体中的JSON