快取 UserDetails

Spring Security 支援使用 CachingUserDetailsService 快取 UserDetails。另外,您也可以使用 Spring Framework 的 @Cacheable 註解。無論是哪種情況,您都需要停用憑據擦除,以便驗證從快取中檢索到的密碼。

CachingUserDetailsService

Spring Security 的 CachingUserDetailsService 實現了 UserDetailsService,提供了快取 UserDetails 的支援。CachingUserDetailsService 透過委託給提供的 UserDetailsService 來提供 UserDetails 的快取支援。結果隨後儲存在 UserCache 中,以減少後續呼叫的計算量。

以下示例簡單地定義了一個 @Bean,它封裝了 UserDetailsService 的具體實現和一個用於快取 UserDetailsUserCache

提供一個 CachingUserDetailsService @Bean
  • Java

  • Kotlin

@Bean
public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
	UserDetailsService delegate = ...;
    CachingUserDetailsService service = new CachingUserDetailsService(delegate);
    service.setUserCache(userCache);
    return service;
}
@Bean
fun cachingUserDetailsService(userCache: UserCache): CachingUserDetailsService {
    val delegate: UserDetailsService = ...
    val service = CachingUserDetailsService(delegate)
    service.userCache = userCache
    return service
}

@Cacheable

另一種方法是在您的 UserDetailsService 實現中使用 Spring Framework 的 @Cacheable 註解,透過 username 快取 UserDetails。這種方法的優點是配置更簡單,特別是如果您的應用中已經在其他地方使用了快取。

以下示例假設快取已配置,並在 loadUserByUsername 方法上標註了 @Cacheable 註解

標註了 @CacheableUserDetailsService
  • Java

  • Kotlin

@Service
public class MyCustomUserDetailsImplementation implements UserDetailsService {

    @Override
    @Cacheable
    public UserDetails loadUserByUsername(String username) {
        // some logic here to get the actual user details
        return userDetails;
    }
}
@Service
class MyCustomUserDetailsImplementation : UserDetailsService {

    @Cacheable
    override fun loadUserByUsername(username: String): UserDetails {
        // some logic here to get the actual user details
        return userDetails
    }
}

停用憑據擦除

無論您使用 CachingUserDetailsService 還是 @Cacheable,您都需要停用 憑據擦除,以便從快取中檢索到的 UserDetails 包含用於驗證的 password。以下示例透過配置 Spring Security 提供的 AuthenticationManagerBuilder 來停用全域性 AuthenticationManager 的憑據擦除

停用全域性 AuthenticationManager 的憑據擦除
  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		// ...
		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService() {
		// Return a UserDetailsService that caches users
		// ...
	}

	@Autowired
	public void configure(AuthenticationManagerBuilder builder) {
		builder.eraseCredentials(false);
	}

}
import org.springframework.security.config.annotation.web.invoke

@Configuration
@EnableWebSecurity
class SecurityConfig {

	@Bean
	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		// ...
		return http.build()
	}

	@Bean
	fun userDetailsService(): UserDetailsService {
		// Return a UserDetailsService that caches users
		// ...
	}

	@Autowired
	fun configure(builder: AuthenticationManagerBuilder) {
		builder.eraseCredentials(false)
	}

}