Subject: [PATCH] boot4_userCache
---
Index: src/main/java/ru/javaops/bootjava/app/config/AppConfig.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/app/config/AppConfig.java b/src/main/java/ru/javaops/bootjava/app/config/AppConfig.java
--- a/src/main/java/ru/javaops/bootjava/app/config/AppConfig.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/main/java/ru/javaops/bootjava/app/config/AppConfig.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -4,7 +4,6 @@
import com.fasterxml.jackson.annotation.PropertyAccessor;
import lombok.extern.slf4j.Slf4j;
import org.h2.tools.Server;
-import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@@ -22,7 +21,6 @@
@Configuration
@Slf4j
-@EnableCaching
public class AppConfig {
@Profile("!test")
Index: src/main/java/ru/javaops/bootjava/app/config/SecurityConfig.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/app/config/SecurityConfig.java b/src/main/java/ru/javaops/bootjava/app/config/SecurityConfig.java
--- a/src/main/java/ru/javaops/bootjava/app/config/SecurityConfig.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/main/java/ru/javaops/bootjava/app/config/SecurityConfig.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -2,15 +2,22 @@
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.CachingUserDetailsService;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@@ -25,26 +32,41 @@
@Configuration
@EnableWebSecurity
+@EnableCaching
@Slf4j
@AllArgsConstructor
public class SecurityConfig {
public static final PasswordEncoder PASSWORD_ENCODER = PasswordEncoderFactories.createDelegatingPasswordEncoder();
private final UserRepository userRepository;
+ private final CacheManager cacheManager;
@Bean
PasswordEncoder passwordEncoder() {
return PASSWORD_ENCODER;
}
+ @Bean
+ UserCache userCache() {
+ return new SpringCacheBasedUserCache(cacheManager.getCache("users"));
+ }
+
+ // https://www.phind.com/search/cmihyvg060000356u4nci6bie
@Bean
UserDetailsService userDetailsService() {
- return email -> {
+ CachingUserDetailsService service = new CachingUserDetailsService(email -> {
log.debug("Authenticating '{}'", email);
Optional optionalUser = userRepository.findByEmailIgnoreCase(email);
return new AuthUser(optionalUser.orElseThrow(
() -> new UsernameNotFoundException("User '" + email + "' was not found")));
- };
+ });
+ service.setUserCache(userCache());
+ return service;
+ }
+
+ @Autowired
+ public void configure(AuthenticationManagerBuilder builder) {
+ builder.eraseCredentials(false);
}
//https://stackoverflow.com/a/76538979/548473
Index: src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java b/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -2,6 +2,7 @@
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserCache;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import ru.javaops.bootjava.user.model.User;
@@ -12,6 +13,9 @@
public abstract class AbstractUserController {
protected final Logger log = getLogger(getClass());
+ @Autowired
+ protected UserCache userCache;
+
@Autowired
protected UserRepository repository;
Index: src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java b/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -18,7 +18,6 @@
@RestController
@RequestMapping(value = AdminUserController.REST_URL, produces = MediaType.APPLICATION_JSON_VALUE)
-// TODO: cache only most requested, seldom changed data!
public class AdminUserController extends AbstractUserController {
static final String REST_URL = "/api/admin/users";
@@ -33,7 +32,9 @@
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable int id) {
+ User user = repository.getExisted(id);
super.delete(id);
+ userCache.removeUserFromCache(user.getEmail());
}
@GetMapping
@@ -59,6 +60,7 @@
log.info("update {} with id={}", user, id);
assureIdConsistent(user, id);
repository.prepareAndSave(user);
+ userCache.removeUserFromCache(user.getEmail());
}
@GetMapping("/by-email")
@@ -74,5 +76,6 @@
log.info(enabled ? "enable {}" : "disable {}", id);
User user = repository.getExisted(id);
user.setEnabled(enabled);
+ userCache.removeUserFromCache(user.getEmail());
}
}
\ No newline at end of file
Index: src/main/java/ru/javaops/bootjava/user/web/ProfileController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java b/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -22,7 +22,6 @@
@RestController
@RequestMapping(value = ProfileController.REST_URL, produces = MediaType.APPLICATION_JSON_VALUE)
@Slf4j
-// TODO: cache only most requested data!
public class ProfileController extends AbstractUserController {
static final String REST_URL = "/api/profile";
@@ -36,6 +35,7 @@
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@AuthenticationPrincipal AuthUser authUser) {
super.delete(authUser.id());
+ userCache.removeUserFromCache(authUser.getUsername());
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@@ -57,5 +57,6 @@
assureIdConsistent(userTo, authUser.id());
User user = authUser.getUser();
repository.prepareAndSave(UsersUtil.updateFromTo(user, userTo));
+ userCache.removeUserFromCache(authUser.getUsername());
}
}
\ No newline at end of file
Index: src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java b/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java
--- a/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java (revision c5d1f7b9b7a24c28fed510a64ca4e332f31e2adf)
+++ b/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java (revision 8f36adf661e041a5462f9701aeb1d886974f6945)
@@ -61,7 +61,7 @@
perform(MockMvcRequestBuilders.delete(REST_URL_SLASH + USER_ID))
.andDo(print())
.andExpect(status().isNoContent());
- assertFalse(repository.findById(USER_ID).isPresent());
+ assertFalse(repository.findByEmailIgnoreCase(USER_MAIL).isPresent());
}
@Test