diff --git a/pom.xml b/pom.xml
index 41235dcc26..a24e3d4667 100644
--- a/pom.xml
+++ b/pom.xml
@@ -147,6 +147,7 @@
spring-rest-docs
spring-rest
spring-security-basic-auth
+ spring-security-cache-control
spring-security-client/spring-security-jsp-authentication
spring-security-client/spring-security-jsp-authorize
spring-security-client/spring-security-jsp-config
diff --git a/spring-security-cache-control/pom.xml b/spring-security-cache-control/pom.xml
new file mode 100644
index 0000000000..c30b0cd1aa
--- /dev/null
+++ b/spring-security-cache-control/pom.xml
@@ -0,0 +1,88 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-security-cache-control
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.4.3.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.security
+ spring-security-core
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework.security
+ spring-security-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+ javax.servlet
+ javax.servlet-api
+ ${javax.servlet-api.version}
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.hamcrest
+ hamcrest-core
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+ org.springframework
+ spring-test
+
+
+
+ com.jayway.restassured
+ rest-assured
+ ${rest-assured.version}
+
+
+
+
+ 3.1.0
+ 2.9.0
+
+
+
\ No newline at end of file
diff --git a/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/AppRunner.java b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/AppRunner.java
new file mode 100644
index 0000000000..28ff90a570
--- /dev/null
+++ b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/AppRunner.java
@@ -0,0 +1,12 @@
+package com.baeldung.cachecontrol;
+
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class AppRunner {
+ public static void main(String[] args) {
+ SpringApplication.run(AppRunner.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/ResourceEndpoint.java b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/ResourceEndpoint.java
new file mode 100644
index 0000000000..9f756b5ab4
--- /dev/null
+++ b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/ResourceEndpoint.java
@@ -0,0 +1,44 @@
+package com.baeldung.cachecontrol;
+
+
+import com.baeldung.cachecontrol.model.TimestampDto;
+import com.baeldung.cachecontrol.model.UserDto;
+import org.springframework.http.CacheControl;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.concurrent.TimeUnit;
+
+@Controller
+public class ResourceEndpoint {
+
+ @RequestMapping(value = "/default/users/{name}", method = RequestMethod.GET)
+ public ResponseEntity getUserWithDefaultCaching(@PathVariable(value = "name") String name) {
+ return ResponseEntity.ok(new UserDto(name));
+ }
+
+ @RequestMapping(value = "/users/{name}", method = RequestMethod.GET)
+ public ResponseEntity getUser(@PathVariable(value = "name") String name) {
+ return ResponseEntity.ok()
+ .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
+ .body(new UserDto(name));
+ }
+
+ @RequestMapping(value = "/timestamp", method = RequestMethod.GET)
+ public ResponseEntity getServerTimestamp() {
+ return ResponseEntity.ok()
+ .cacheControl(CacheControl.noStore())
+ .body(new TimestampDto(LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()));
+ }
+
+ @RequestMapping(value = "/private/users/{name}", method = RequestMethod.GET)
+ public ResponseEntity getUserNotCached(@PathVariable("name") String name) {
+ return ResponseEntity.ok()
+ .body(new UserDto(name));
+ }
+}
diff --git a/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/config/SpringSecurityConfig.java b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/config/SpringSecurityConfig.java
new file mode 100644
index 0000000000..b4127e9b71
--- /dev/null
+++ b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/config/SpringSecurityConfig.java
@@ -0,0 +1,17 @@
+package com.baeldung.cachecontrol.config;
+
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {}
+}
diff --git a/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/TimestampDto.java b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/TimestampDto.java
new file mode 100644
index 0000000000..cb3befacac
--- /dev/null
+++ b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/TimestampDto.java
@@ -0,0 +1,10 @@
+package com.baeldung.cachecontrol.model;
+
+
+public class TimestampDto {
+ public final Long timestamp;
+
+ public TimestampDto(Long timestamp) {
+ this.timestamp = timestamp;
+ }
+}
diff --git a/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/UserDto.java b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/UserDto.java
new file mode 100644
index 0000000000..a41cb31d80
--- /dev/null
+++ b/spring-security-cache-control/src/main/java/com/baeldung/cachecontrol/model/UserDto.java
@@ -0,0 +1,11 @@
+package com.baeldung.cachecontrol.model;
+
+
+public class UserDto {
+ public final String name;
+
+ public UserDto(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/spring-security-cache-control/src/test/java/com/baeldung/cachecontrol/ResourceEndpointLiveTest.java b/spring-security-cache-control/src/test/java/com/baeldung/cachecontrol/ResourceEndpointLiveTest.java
new file mode 100644
index 0000000000..94b6052ba4
--- /dev/null
+++ b/spring-security-cache-control/src/test/java/com/baeldung/cachecontrol/ResourceEndpointLiveTest.java
@@ -0,0 +1,72 @@
+package com.baeldung.cachecontrol;
+
+import com.jayway.restassured.http.ContentType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.context.embedded.LocalServerPort;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static com.jayway.restassured.RestAssured.given;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AppRunner.class)
+public class ResourceEndpointLiveTest {
+
+ @LocalServerPort
+ private int serverPort;
+
+ @Test
+ public void whenGetRequestForUser_shouldRespondWithDefaultCacheHeaders() {
+ given()
+ .when()
+ .get(getBaseUrl() + "/default/users/Michael")
+ .then()
+ .headers("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
+ .header("Pragma", "no-cache");
+ }
+
+ @Test
+ public void whenGetRequestForUser_shouldRespondMaxAgeCacheControl() {
+ given()
+ .when()
+ .get(getBaseUrl() + "/users/Michael")
+ .then()
+ .header("Cache-Control", "max-age=60");
+ }
+
+ @Test
+ public void givenServiceEndpoint_whenGetRequestForUser_shouldResponseWithCacheControlMaxAge() {
+ given()
+ .when()
+ .get(getBaseUrl() + "/users/Michael")
+ .then()
+ .contentType(ContentType.JSON).and().statusCode(200).and()
+ .header("Cache-Control", "max-age=60");
+ }
+
+ @Test
+ public void givenServiceEndpoint_whenGetRequestForNotCacheableContent_shouldResponseWithCacheControlNoCache() {
+ given()
+ .when()
+ .get(getBaseUrl() + "/timestamp")
+ .then()
+ .contentType(ContentType.JSON).and().statusCode(200).and()
+ .header("Cache-Control", "no-store");
+ }
+
+ @Test
+ public void givenServiceEndpoint_whenGetRequestForPrivateUser_shouldResponseWithSecurityDefaultCacheControl() {
+ given()
+ .when()
+ .get(getBaseUrl() + "/private/users/Michael")
+ .then()
+ .contentType(ContentType.JSON).and().statusCode(200).and()
+ .header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+
+ private String getBaseUrl() {
+ return "http://localhost:" + serverPort;
+ }
+
+}
\ No newline at end of file