spring - 如何在 Spring Boot 中为包含匿名用户表单的任何页面处理会话创建和添加隐藏的输入 csrf 令牌?
问题描述
我介绍问题:
当我启动应用程序并输入网址“/home”时。主页显示但不正确(模板组织得不好),我收到异常TemplateInputException。过了一会儿,如果我刷新主页和其他页面,它会恢复正常,但如果我转到“/login”,然后我注销会将我重定向到主页视图,同样的问题会再次出现。
Stacktrace 控制台:
org.thymeleaf.exceptions.TemplateInputException:模板解析时出错(模板:“类路径资源[templates/home.html]”)...
原因:org.attoparser.ParseException:在 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”时出错(模板:“home” - 第 2494 行,第 10 列)
原因:java.lang.IllegalStateException:在 org.apache.catalina.connector.Request.doGetSession(Request.java:2995) ~[tomcat-embed-core-8.5.14.罐子:8.5.14]
...
在 org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.saveToken(HttpSessionCsrfTokenRepository.java:63) ~[spring-security-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] 在 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:
@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;
}
}
}
解决方案
这是解决“无法创建会话和 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())
}
推荐阅读
- reactjs - 如何使用 redux get 函数更新某些状态?值在片场未正确更新
- returnn - 使用多个 GPU 进行训练
- python - 将值分配给 TCP 服务器寄存器的 pymodbus 语法是什么?
- bash - 为什么转义字符和正则表达式不能很好地与 sed 命令配合使用?
- angularjs - angular.equals() 的用法
- vb.net - 寻找使用 api 数据的最简单方法,以允许用户选择特定部分,并保存到其他数据库
- javascript - req.files 在ajax调用后给出NULL,文件名不正确
- node.js - 无法使用 Node / Express 在 POST 请求中发送正确的响应
- python - Paraview - 使用 python 脚本以 x3d 格式导出数据
- c++ - 如何在 C/C++ 中计算 n=100 的加泰罗尼亚数字?