如何在Spring Boot中为包含匿名用户表单的任何页面处理会话创建和添加隐藏输入csrf标记?

时间:2018-05-06 11:41:16

标签: spring spring-mvc spring-boot spring-security thymeleaf

我介绍问题:

当我启动应用程序时,我输入了网址" / home"。主页显示但不正确(模板组织不好),我收到异常 TemplateInputException 。过了一会儿,如果我刷新主页和其他页面它恢复正常但是如果我去" / login",并且我注销将我重定向到主视图,同样的问题又回来了

Stacktrace控制台:

  

org.thymeleaf.exceptions.TemplateInputException:发生错误   在模板解析期间(模板:"类路径资源   [templates / home.html]")...

     

引起:org.attoparser.ParseException :执行处理器时出错   ' org.thymeleaf.spring4.processor.SpringActionTagProcessor' (模板:   "家" - 第2494行,第10栏)   org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)   〜[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE] ...

     

引起:org.thymeleaf.exceptions.TemplateProcessingException :错误   在执行处理器期间   ' org.thymeleaf.spring4.processor.SpringActionTagProcessor' (模板:   "家" - 第2494行,第10栏)

     

引起:java.lang.IllegalStateException:在提交响应后无法创建会话   org.apache.catalina.connector.Request.doGetSession(Request.java:2995)   〜[Tomcat的嵌入芯-8.5.14.jar:8.5.14]

     

...

     

at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.saveToken(HttpSessionCsrfTokenRepository.java:63)   〜[spring-security-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at   org.springframework.security.web.csrf.LazyCsrfTokenRepository $ SaveOnAccessCsrfToken.saveTokenIfNecessary(LazyCsrfTokenRepository.java:176)   〜[spring-security-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at   org.springframework.security.web.csrf.LazyCsrfTokenRepository $ SaveOnAccessCsrfToken.getToken(LazyCsrfTokenRepository.java:128)   〜[spring-security-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at   org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor。的 getExtraHiddenFields (CsrfRequestDataValueProcessor.java:71)   〜[spring-security-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] ......

代码来源:

问题出在此行的home.html的联系表单中:th:action="@{/home/contact}" th:object="${mailForm}"

<form id="contact-form" method="post" action="/home/contact}" 
    th:action="@{/home/contact}" th:object="${mailForm}"
    role="form">
    <!-- <input type="hidden" name="${_csrf.parameterName}" 
    value="${_csrf.token}" /> -->
    <input type="text" name="senderName" th:field="*{senderName}"> 
    <input type="text" name="senderLastName" th:field="*{senderLastName}">  
    <input type="email" name="senderEmail" th:field="*{senderEmail}">            
    <textarea name="message" th:field="*{message}"></textarea>
    <button type="submit">Send Message</button>
</form>

我认为这是csrf令牌的问题。我尝试在我的表单中添加此行<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />,并且默认情况下由Spring Security启用csrf保护,但它不起作用。

调用服务以发送邮件的控制器:

@Controller
public class HomeController {
    @Autowired
    private EmailService emailService;
    @Autowired
    private MailValidator mailValidator;

    // some other code like @InitBinder methode ...

    // method to post mailForm
    @PostMapping("/home/contact")
    public String contactUsHome(@Valid @ModelAttribute("mailForm") final MailForm mailForm, BindingResult bindingResult)
            throws MessagingException {

        if (bindingResult.hasErrors()) {
            return HOME_VIEW;
        } else {
            mailForm.setRecipientEmail(recipientEmail);
            Mail mail = DTOUtil.map(mailForm, Mail.class);
            emailService.sendSimpleMail(mail);
            return REDIRECT_HOME_VIEW;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

这是解决“无法创建会话和CSRF令牌”问题的方法。

在spring安全配置类中,我刚添加了这一行.and().csrf().csrfTokenRepository(..),一切运行良好。

@Override
protected void configure(HttpSecurity http) throws Exception {
     http.authorizeRequests()
     //some another line of code...
     .and().csrf().csrfTokenRepository(new HttpSessionCsrfTokenRepository())
}