Lorsque Spring Security est utilisé sur Spring Boot, le CsrfRequestDataValueProcessor
(classe de sortie de la valeur du jeton CSRF vers le caché du formulaire) fourni par Spring Security est appliqué et le RequestDataValueProcessor spécifique au projet ne peut pas être appliqué.
C'est ... Il semble que le problème de Spring Boot (gh-4676) discute de la façon de le gérer, mais c'est toujours une conclusion. Ne semble pas apparaître.
En cause ...
BeanDefinitionRegistryPostProcessor
@ AutoConfigureAfter
pour remplacer la définition du bean dans SecurityAutoConfiguration.class
Est présenté comme une solution de contournement.
Cette fois, je vais essayer de créer ma propre classe AutoConfigure et utiliser @ AutoConfigureAfter
pour remplacer la définition de Bean dans SecurityAutoConfiguration.class
.
Le «RequestDataValueProcessor» spécifique au projet génère des paramètres communs (_s = date et heure du système en millisecondes) pour éviter la mise en cache dans l'URL sous les éléments «form» et «a».
La classe créée cette fois ne considère pas du tout la polyvalence et adopte une méthode d'implémentation qui applique l'implémentation spécifique au projet RequestDataValueProcessor
à l'application tout en conservant les fonctions fournies par CsrfRequestDataValueProcessor
.
Note:
Si vous considérez la polyvalence ... Il est préférable de créer une classe composite de
RequestDataValueProcessor
qui délègue le traitement à plusieursRequestDataValueProcessor
s.
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) //★★★ Points ici[1]
public class MyRequestDataValueProcessorAutoConfiguration {
@Bean
RequestDataValueProcessor requestDataValueProcessor() { //★★★ Points ici[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]
En permettant à votre propre classe AutoConfigure d'être appelée après SecurityAutoConfiguration
, vous pouvez remplacer la définition de Bean fournie par Spring Boot (Spring Security) avec votre propre classe AutoConfigure.
[2]
Pour remplacer la définition du bean, le nom du bean doit être "requestDataValueProcessor" ".
Fondamentalement, il délègue le processus à CsrfRequestDataValueProcessor
et l'implémente pour ajouter un paramètre d'évitement de cache aux valeurs de retour de processAction
et processUrl
.
Pour rendre la classe de configuration créée reconnue comme classe de configuration automatique, créez src / main / resources / META-INF / spring.factories
et utilisez la valeur de clé de propriété ʻorg.springframework.boot.autoconfigure.EnableAutoConfiguration`. Vous devez spécifier la classe dans laquelle vous avez créé.
src/main/resources/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyRequestDataValueProcessorAutoConfiguration
Créons une vue simple pour la vérification des opérations.
<!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}"> <!--★★★ Points ici[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> <!--★★★ Points ici[4] -->
</div>
</body>
</html>
[3]
L'URL spécifiée dans th: action
est traitée par la méthode RequestDataValueProcessor # processAction
.
[4]
L'URL spécifiée dans th: href
est traitée par la méthode RequestDataValueProcessor # processUrl
.
Lorsque le HTML ci-dessus est exécuté sur Spring Boot, le HTML suivant est généré. Il y a un paramètre d'évitement de cache dans l'URL de l'attribut ʻaction de l'élément "
form "et de l'attribut" href
de l'élément "ʻa", et le paramètre
hiddenpour lier la valeur du jeton CSRF dans l'élément
form`. Vous pouvez voir que l'élément est sorti.
<!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"> <!--★★★ Le paramètre d'évitement du cache est donné-->
<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> <!--★★★ Le lien caché de la valeur du jeton CSRF est donné.-->
</div>
<a href="/demo?_s=1488222896002">Reload</a> <!--★★★ Le paramètre d'évitement du cache est donné-->
</div>
</body>
</html>
RequestDataValueProcessor # processUrl
est lié à la fonction de redirection de Spring MVC, nous allons donc vérifier l'opération ici également.
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"; //★★★ Points ici[5]
}
static class DemoForm {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
}
[5]
L'URL spécifiée lors de l'utilisation de la fonctionnalité de redirection Spring MVC est traitée par la méthode RequestDataValueProcessor # processUrl
.
Si vous vérifiez l'URL de redirection avec l'outil de développement du navigateur, vous pouvez voir que le paramètre d'évitement de cache est correctement attribué.
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 #★★★ Le paramètre d'évitement du cache est donné
Content-Language: en-US
Content-Length: 0
Date: Mon, 27 Feb 2017 19:23:57 GMT
En créant ma propre classe AutoConfigure, j'ai pu faire coexister CsrfRequestDataValueProcessor
et mon propre RequestDataValueProcessor
.
Il a également été confirmé qu'en utilisant RequestDataValueProcessor
, des paramètres communs peuvent être ajoutés aux URL gérées sous Spring MVC. Cependant ... Lors de la gestion d'URL en dehors de la gestion Spring MVC (par exemple, lors de la gestion directe de la méthode de HttpServletResponse
), elle n'est pas sous la juridiction de RequestDataValueProcessor
, donc les paramètres communs ne peuvent pas être affectés.
Si vous souhaitez ajouter des paramètres communs aux URL non gérées par Spring MVC, vous devez créer HttpServletResponseWrapper
pour donner des paramètres communs, l'envelopper dans la classe créée par Servlet Filter et appeler le traitement suivant. Je vais.
Recommended Posts