Es gibt durchaus gute Tutorials und Examples für Spring Boot Security. Nur benutzen die alle Thymeleaf als Templating Engine. Und Thymeleaf hat eine Besonderheit: Wenn man im Form “th:action” statt “action” verwendet, dann wird automatisch ein hidden Input Field mit dem CSRF-Token injected!
Wenn man stattdessen bsplw. Velocity verwendet, und das Template 1:1 übersetzt, merkt man nicht, dass etwas fehlt m( Der Server gibt “403 Forbidden” ohne weitere Fehlermeldung zurück (Tipp zum Debuggen: Der Request wird irgendwann auf die Error-Route umgebogen, aber der Fehler (hier noch inklusive Fehlermeldung) steht im Response-Object).
Offenbar muss man den Token dann manuell dem Template übergeben (Quelle, weicht aber leicht ab):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@RequestMapping(value = "/login") public String login( @RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout", required = false) String logout, HttpServletRequest request, Map<String, Object> model) { CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class .getName()); if (csrfToken != null) { model.put("_csrf",csrfToken.getToken()); } return "pages/login"; } |
1 2 3 4 5 6 |
private static final Logger logger = Logger.getLogger(UiController.class); // ... Authentication auth = SecurityContextHolder.getContext().getAuthentication(); logger.debug("User " + auth.getName() + " is here!"); |
Update
Übrigens: Hier wird beschrieben, wie man in Thymeleaf den Token in jeden Ajax-Request bekommt. Leider funktioniert das so nicht, denn um den Platzhalter zu ersetzen, muss man th:content verwenden (Quelle indirekt), sonst wird der Platzhalter nicht ausgewertet m(
1 2 |
<meta name="_csrf" th:content="${_csrf.token}" /> <meta name="_csrf_header" th:content="${_csrf.headerName}" /> |
Dann: Siehe hier für das Absetzen der Requests (in jQuery oder Angular)