When Spring Security is used on Spring Boot, the CsrfRequestDataValueProcessor (class for outputting the CSRF token value to the hidden of the form) provided by Spring Security is applied, and the project-specific RequestDataValueProcessor cannot be applied.
This is ... Spring Boot Issue (gh-4676) seems to be discussing how to deal with it, but it's still a conclusion. Does not seem to appear.
In Issue ...
BeanDefinitionRegistryPostProcessor@ AutoConfigureAfter to override the Bean definition in SecurityAutoConfiguration.classIs introduced as a workaround.
This time, I'll try to create my own AutoConfigure class and use @ AutoConfigureAfter to override the Bean definition in SecurityAutoConfiguration.class.
In addition, the project-specific RequestDataValueProcessor outputs a common parameter (_s = system date and time epoch milliseconds) to avoid caching in the URL in the form and ʻa` elements.
The class created this time does not consider versatility at all, and adopts an implementation method that applies the project-specific RequestDataValueProcessor implementation to the application while retaining the functions provided by CsrfRequestDataValueProcessor.
Note:
If you consider versatility ... It is better to create a Composite class of
RequestDataValueProcessorthat delegates processing to multipleRequestDataValueProcessors.
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) //★★★ Here points[1]
public class MyRequestDataValueProcessorAutoConfiguration {
	@Bean
	RequestDataValueProcessor requestDataValueProcessor() { //★★★ Here points[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]
By allowing your own AutoConfigure class to be called after SecurityAutoConfiguration, you can overwrite the Bean definition provided by Spring Boot (Spring Security) with your own AutoConfigure class.
[2]
In order to override the bean definition, the bean name must be " requestDataValueProcessor ".
Basically, it delegates the process to CsrfRequestDataValueProcessor and implements it to add a cache avoidance parameter to the return values of processAction and processUrl.
In order to recognize the created configuration class as AutoConfigure class, create src / main / resources / META-INF / spring.factories and set the property key value of ʻorg.springframework.boot.autoconfigure.EnableAutoConfiguration`. You need to specify the class you created in.
src/main/resources/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyRequestDataValueProcessorAutoConfiguration
Let's create a simple View for operation verification.
<!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}"> <!--★★★ Here points[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> <!--★★★ Here points[4] -->
</div>
</body>
</html>
[3]
The URL specified in th: action is processed by the RequestDataValueProcessor # processAction method.
[4]
The URL specified in th: href is processed by the RequestDataValueProcessor # processUrl method.
When the above HTML is executed on Spring Boot, the following HTML will be generated. The URL of the " form element's ʻaction attribute" and the "ʻa element's href attribute "has a cache avoidance parameter, and the hidden for linking the CSRF token value in the form element. You can see that the element is output.
<!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"> <!--★★★ Cache avoidance parameter is given-->
            <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> <!--★★★ Hidden of CSRF token value linkage is given-->
    </div>
    <a href="/demo?_s=1488222896002">Reload</a> <!--★★★ Cache avoidance parameter is given-->
</div>
</body>
</html>
RequestDataValueProcessor # processUrl is linked with the redirect function of Spring MVC, so let's check the operation there as well.
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"; //★★★ Here points[5]
	}
	static class DemoForm {
		private String title;
		public String getTitle() {
			return title;
		}
		public void setTitle(String title) {
			this.title = title;
		}
	}
}
[5]
The URL specified when using the Spring MVC redirect function is processed by the RequestDataValueProcessor # processUrl method.
If you check the redirect URL with your browser's developer tools, you can see that the cache avoidance parameter is properly assigned.
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 #★★★ Cache avoidance parameter is given
Content-Language: en-US
Content-Length: 0
Date: Mon, 27 Feb 2017 19:23:57 GMT
By creating my own AutoConfigure class, I was able to make CsrfRequestDataValueProcessor and my own RequestDataValueProcessor coexist.
Also, by using RequestDataValueProcessor, it was confirmed that common parameters can be added to URLs handled under Spring MVC. However ... When handling URLs outside of Spring MVC management (for example, when handling the method of HttpServletResponse directly), it is not under the jurisdiction of RequestDataValueProcessor, so common parameters cannot be assigned.
If you want to add common parameters to URLs not managed by Spring MVC, you need to create HttpServletResponseWrapper to add common parameters, wrap it in the class created by Servlet Filter, and call the subsequent processing. I will.
Recommended Posts