缓存 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

另一种方法是使用 Spring 框架的 @Cacheable 在您的 UserDetailsService 实现中,通过 username 缓存 UserDetails。这种方法的优点是配置更简单,尤其是在您已经在应用程序的其他地方使用缓存的情况下。

以下示例假设缓存已配置,并使用 @Cacheable 注释 loadUserByUsername

使用 @Cacheable 注释的 UserDetailsService
  • 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)
	}

}