Wenn Spring Security beim Spring Boot verwendet wird, wird der von Spring Security bereitgestellte "CsrfRequestDataValueProcessor" (eine Klasse zum Ausgeben des CSRF-Token-Werts an das ausgeblendete Formular) angewendet, und der projektspezifische "RequestDataValueProcessor" kann nicht angewendet werden. Dies ist ... Es scheint, dass das Problem von Spring Boot (gh-4676) diskutiert, wie man damit umgeht, aber es ist immer noch eine Schlussfolgerung. Scheint nicht zu erscheinen.
In Ausgabe ...
BeanDefinitionRegistryPostProcessor
um?@ AutoConfigureAfter
die Bean-Definition in SecurityAutoConfiguration.class
Wird als Problemumgehung eingeführt.
Dieses Mal werde ich versuchen, meine eigene AutoConfigure-Klasse zu erstellen und @ AutoConfigureAfter
zu verwenden, um die Bean-Definition in SecurityAutoConfiguration.class
zu überschreiben.
Der projektspezifische RequestDataValueProcessor
gibt allgemeine Parameter aus (_s = Millisekunden für Systemdatum und -zeit), um ein Zwischenspeichern der URL in den Elementen form
und a
zu vermeiden.
Die diesmal erstellte Klasse berücksichtigt die Vielseitigkeit überhaupt nicht und verwendet eine Implementierungsmethode, die die projektspezifische Implementierung von "RequestDataValueProcessor" auf die Anwendung anwendet, während die von "CsrfRequestDataValueProcessor" bereitgestellten Funktionen beibehalten werden.
Note:
Wenn Sie die Vielseitigkeit berücksichtigen ... Es ist besser, eine zusammengesetzte Klasse von "RequestDataValueProcessor" zu erstellen, die die Verarbeitung an mehrere "RequestDataValueProcessor" delegiert.
package com.example;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.web.util.UriComponentsBuilder;
@Configuration
@AutoConfigureAfter(SecurityAutoConfiguration.class) //★★★ Hier Punkte[1]
public class MyRequestDataValueProcessorAutoConfiguration {
@Bean
RequestDataValueProcessor requestDataValueProcessor() { //★★★ Hier Punkte[2]
CsrfRequestDataValueProcessor csrfRequestDataValueProcessor = new CsrfRequestDataValueProcessor();
return new RequestDataValueProcessor() {
@Override
public String processAction(HttpServletRequest request, String action, String httpMethod) {
return addCachePreventQueryParameter(csrfRequestDataValueProcessor.processAction(request, action, httpMethod));
}
@Override
public String processFormFieldValue(HttpServletRequest request, String name, String value, String type) {
return csrfRequestDataValueProcessor.processFormFieldValue(request, name, value, type);
}
@Override
public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
return csrfRequestDataValueProcessor.getExtraHiddenFields(request);
}
@Override
public String processUrl(HttpServletRequest request, String url) {
return addCachePreventQueryParameter(csrfRequestDataValueProcessor.processUrl(request, url));
}
private String addCachePreventQueryParameter(String url) {
return UriComponentsBuilder.fromUriString(url).queryParam("_s", System.currentTimeMillis()).build().encode()
.toUriString();
}
};
}
}
[1] Indem Sie zulassen, dass Ihre eigene AutoConfigure-Klasse nach "SecurityAutoConfiguration" aufgerufen wird, können Sie die von Spring Boot (Spring Security) bereitgestellte Bean-Definition mit Ihrer eigenen AutoConfigure-Klasse überschreiben. [2] Um die Bean-Definition zu überschreiben, muss der Bean-Name "requestDataValueProcessor" sein.
Grundsätzlich delegiert es den Prozess an "CsrfRequestDataValueProcessor" und implementiert ihn, um den Rückgabewerten von "processAction" und "processUrl" einen Cache-Vermeidungsparameter hinzuzufügen.
Um die erstellte Konfigurationsklasse als AutoConfigure-Klasse zu erkennen, erstellen Sie "src / main / resources / META-INF / spring.factories" und verwenden Sie den Eigenschaftsschlüsselwert "org.springframework.boot.autoconfigure.EnableAutoConfiguration". Sie müssen die Klasse angeben, in der Sie erstellt haben.
src/main/resources/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyRequestDataValueProcessorAutoConfiguration
Lassen Sie uns eine einfache Ansicht für die Betriebsüberprüfung erstellen.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" type="text/css"/>
</head>
<body>
<div class="container">
<h1>Demo</h1>
<div id="demoForm">
<form action="index.html" method="post" class="form-horizontal"
th:action="@{/demo}" th:object="${demoForm}"> <!--★★★ Hier Punkte[3] -->
<div class="form-group">
<label for="title" class="col-sm-1 control-label">Title</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="title" th:field="*{title}"/>
<span class="text-error" th:errors="*{title}">error message</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<button type="submit" class="btn btn-default">Create</button>
</div>
</div>
</form>
</div>
<a href="index.html" th:href="@{/demo}">Reload</a> <!--★★★ Hier Punkte[4] -->
</div>
</body>
</html>
[3]
Die in th: action
angegebene URL wird von der Methode RequestDataValueProcessor # processAction
verarbeitet.
[4]
Die in th: href
angegebene URL wird von der Methode RequestDataValueProcessor # processUrl
verarbeitet.
Wenn der obige HTML-Code beim Spring Boot ausgeführt wird, wird der folgende HTML-Code generiert. Die URL des "action" -Attributs des "form" -Elements und des "href" -Attributs des "a" -Elements enthält einen Cache-Vermeidungsparameter und das "hidden" zum Verknüpfen des CSRF-Token-Werts im "form" -Element. Sie können sehen, dass das Element ausgegeben wird.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" type="text/css" />
</head>
<body>
<div class="container">
<h1>Demo</h1>
<div id="demoForm">
<form action="/demo?_s=1488222896002" method="post" class="form-horizontal"> <!--★★★ Der Cache-Vermeidungsparameter ist angegeben-->
<div class="form-group">
<label for="title" class="col-sm-1 control-label">Title</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="title" name="title" value="" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<button type="submit" class="btn btn-default">Create</button>
</div>
</div>
<input type="hidden" name="_csrf" value="b952a1bf-222a-4a99-b889-6878935a5784" /></form> <!--★★★ Die versteckte Verknüpfung von CSRF-Token-Werten ist angegeben.-->
</div>
<a href="/demo?_s=1488222896002">Reload</a> <!--★★★ Der Cache-Vermeidungsparameter ist angegeben-->
</div>
</body>
</html>
RequestDataValueProcessor # processUrl
ist mit der Umleitungsfunktion von Spring MVC verknüpft. Überprüfen wir also auch dort den Vorgang.
package com.example;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/demo")
@Controller
public class DemoController {
@ModelAttribute
DemoForm setUpForm() {
return new DemoForm();
}
@GetMapping
String index() {
return "index";
}
@PostMapping
String submit(DemoForm form) {
return "redirect:/demo"; //★★★ Hier Punkte[5]
}
static class DemoForm {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
}
[5] Die bei Verwendung der Spring MVC-Umleitungsfunktion angegebene URL wird von der Methode "RequestDataValueProcessor # processUrl" verarbeitet.
Wenn Sie die Umleitungs-URL mit dem Entwicklertool des Browsers überprüfen, können Sie feststellen, dass der Parameter zur Vermeidung von Cache ordnungsgemäß zugewiesen ist.
HTTP/1.1 302
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Location: http://localhost:8080/demo?_s=1488223437196 #★★★ Der Cache-Vermeidungsparameter ist angegeben
Content-Language: en-US
Content-Length: 0
Date: Mon, 27 Feb 2017 19:23:57 GMT
Durch das Erstellen meiner eigenen AutoConfigure-Klasse konnte ich "CsrfRequestDataValueProcessor" und meinen eigenen "RequestDataValueProcessor" koexistieren lassen. Es wurde auch bestätigt, dass mithilfe von "RequestDataValueProcessor" allgemeine Parameter zu den unter Spring MVC behandelten URLs hinzugefügt werden können. Allerdings ... Wenn URLs außerhalb der Spring MVC-Verwaltung verarbeitet werden (z. B. wenn die Methode von "HttpServletResponse" direkt verarbeitet wird), unterliegt sie nicht der Zuständigkeit von "RequestDataValueProcessor", sodass keine allgemeinen Parameter zugewiesen werden können. Wenn Sie URLs, die nicht von Spring MVC verwaltet werden, allgemeine Parameter hinzufügen möchten, müssen Sie "HttpServletResponseWrapper" erstellen, um allgemeine Parameter anzugeben, diese in die von Servlet Filter erstellte Klasse einschließen und die nachfolgende Verarbeitung aufrufen. Ich werde.
Recommended Posts