【问题标题】:Spring Boot, Freemarker, MVC Unit Tests, CsrfSpring Boot、Freemarker、MVC 单元测试、Csrf
【发布时间】:2016-09-11 11:03:47
【问题描述】:

我在 Spring Boot 中使用 Freemarker 并进行 mvc 单元测试。在我的 freemarker 模板中,我有一个隐藏的 csrf 令牌输入字段,如下所示:

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

那我还有一个mvc单元测试:

        @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class MvcTests {

    @Autowired
    WebApplicationContext ctx;

    MockMvc mvc;

    HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository;

    @Before
    public void setUp() throws Exception {
        mvc = webAppContextSetup(ctx).build();
        httpSessionCsrfTokenRepository = new HttpSessionCsrfTokenRepository();
    }


    @Test
    public void testInValidVoucherNumber() throws Exception {
        CsrfToken csrfToken = httpSessionCsrfTokenRepository.generateToken(new MockHttpServletRequest());
        mvc.perform(post("/voucher/claim")
                .sessionAttr("_csrf.parameterName", "_csrf")
                .sessionAttr("_csrf.token", csrfToken.getToken())
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .param("code", "ABC")
                .param("_csrf", csrfToken.getToken()))
                .andExpect(status().isOk())
                .andExpect(view().name("claim-voucher"))
                .andExpect(content().string(containsString("Code is invalid")));
    }
}

当我运行单元测试时,出现以下 freemarker 错误:

    testInValidVoucherNumber(MvcTests)  Time elapsed: 0.904 sec  <<< ERROR!
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> _csrf  [in template "claim-voucher.ftl" at line 25, column 34]

----
Tip: If the failing expression is known to be legally refer to something that's null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
    - Failed at: ${_csrf.parameterName}  [in template "claim-voucher.ftl" at line 25, column 32]
    ~ Reached through: #nested  [in template "layout.ftl" in macro "basic" at line 16, column 9]

这里是控制器:

@RequestMapping(value = "/voucher/claim", method = RequestMethod.POST)
public String checkVoucherCode(@Valid ClaimVoucherForm claimVoucherForm, Model model)  {
    //Business logic
}

似乎 freemarker 无法访问 csrf parameterName 和 csrf 令牌。有没有办法在不更改控制器的情况下包含 csrf 信息或单元测试有问题?

【问题讨论】:

    标签: c# unit-testing spring-boot csrf freemarker


    【解决方案1】:

    会话属性在带有Session. 前缀的模型中可用。您的模板需要更新为以下内容:

    <input type="hidden" name="${Session._csrf.parameterName}" value="${Session._csrf.token}"/>
    

    您还在测试中错误地配置了会话属性。 _csrf.token 表示 Freemarker 将查找名为 _csrf 的对象,然后在该对象上查找名为 token 的属性。您需要分配一个名为_csrf 的会话属性,其中包含parameterNametoken

    Map<String, Object> csrf = new HashMap<String, Object>();
    csrf.put("parameterName", "_csrf");
    csrf.put("token",  csrfToken.getToken());
    mvc.perform(post("/voucher/claim")
                .sessionAttr("_csrf", csrf)
    

    【讨论】:

    • freemarker.core.InvalidReferenceException:以下已评估为 null 或缺失:==> Session._csrf [in template "claim-voucher.ftl" at line 31, column 34]
    【解决方案2】:

    代替:

    .sessionAttr("_csrf.parameterName", "_csrf")
    .sessionAttr("_csrf.token", csrfToken.getToken())
    

    试试:

    .sessionAttr("_csrf", csrfToken)
    

    当您编写 ${_csrf.parameterName} 时,FreeMarker 会在模型变量“_csrf”上查找字段“parameterName”。不适用于模型变量“_csrf.parameterName”。

    也就是说,您必须在测试中将这些参数添加为会话属性,这很奇怪。 Spring Security 的 CsrfFilter 不应该为你做这些吗?

    【讨论】:

    【解决方案3】:

    我用

    解决了同样的问题
    @Import({CsrfFilter.class, HttpSessionCsrfTokenRepository.class})
    

    在我的测试类之上并且没有使用任何.sessionAttr() 调用。

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 2016-05-28
      • 2015-12-20
      • 1970-01-01
      • 2013-07-17
      • 2016-03-15
      • 2017-02-08
      • 2020-08-08
      相关资源
      最近更新 更多