我有一个Spring控制器,经过来自" / user"的经过身份验证的GET返回以下JSON:
{"name":<name>,"token":<csrf-token>}
我尝试为控制器构建一个单元测试,以验证返回的JSON是否包含动态生成的CSRF令牌:
@Autowired
private FilterChainProxy springSecurityFilterChain;
private MockMvc mvc;
@Before
public void setUp()
throws Exception
{
...
mvc = standaloneSetup(controller)
.apply(springSecurity(springSecurityFilterChain))
.build();
}
@Test
public void getUser()
throws Exception
{
CsrfRequestPostProcessor csrfPostProcessor = null;
mvc.perform(get("/user").with(user(Const.USER)).with(csrfPostProcessor = csrf()))
.andExpect(status().isOk())
.andExpect(content().json("{\"name\":\"" + Const.NAME + "\",\"token\":\"" + csrfPostProcessor.toString() + "\"}"));
}
测试失败了:
Failed tests:
ControllerTest.getUser:74 token
Expected: org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors$CsrfRequestPostProcessor@203c20cf
got: 565a95b0-d0bb-4376-a8a0-725a3b16a787
有没有办法解决这个问题,如果没有,有没有办法构建一个使用动态生成的CSRF令牌的替代测试?
答案 0 :(得分:0)
这是一个可能的解决方案 - 构建一个自定义匹配器,以UUID4格式拦截CSRF令牌:
private static Pattern CSRF_PATTERN = Pattern.compile("[\\da-f]{8}-[\\da-f]{4}-4[\\da-f]{3}-[\\da-f]{4}-[\\da-f]{12}");
public static Matcher<String> isCsrf(StringBuilder intercept) {
return new ArgumentMatcher<String>() {
@Override
public boolean matches(Object obj) {
// intercept may be null
Assert.isTrue(obj instanceof DefaultCsrfToken, "obj");
String token = ((DefaultCsrfToken)obj).getToken();
if (intercept != null) {
intercept.setLength(0);
intercept.append(token);
}
java.util.regex.Matcher matcher = CSRF_PATTERN.matcher(token);
return matcher.matches();
}
};
}
然后按如下方式使用:
@Test
public void getUser()
throws Exception
{
StringBuilder token = new StringBuilder();
mvc.perform(get("/user").with(user(Const.USER)).with(csrf()))
.andExpect(status().isOk())
.andExpect(request().attribute("_csrf", isCsrf(csrf)))
.andExpect(content().json("{\"name\":\"" + Const.NAME + "\",\"token\":\"" + token.toString() + "\"}"));
}
作为奖励,您将获得一个CSRF令牌验证器。