gpt4 book ai didi

java - 使用 Spring Boot 缓存用户详细信息

转载 作者:行者123 更新时间:2023-12-04 08:52:11 34 4
gpt4 key购买 nike

我正在尝试实现 UserCache在我的应用程序中,以避免在我使用基本身份验证的情况下多次调用 User 表。我创建了我的 CacheConfig遵循此 topic 的公认答案,其中CachingUserDetailsService用于管理用户缓存。下面是 UserService 的代码, CacheConfigSecurityConfig :


public class UserService implements UserDetailsService {

private final UserRepository userRepository;

public UserService(UserRepository repository) {
this.userRepository = repository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {


AddInUser user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("O usuário " + username + " não pode ser encontrado!"));

UserDetails userDetails = User
.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles("USER")
.build();


return userDetails;
}

@Transactional
public AddInUser save(AddInUser user) {
return userRepository.save(user);
}


}

@EnableCaching
@Configuration
public class CacheConfig {

public static final String USER_CACHE = "userCache";

/**
* Define cache strategy
*
* @return CacheManager
*/
@Bean
public CacheManager cacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<>();

//Failure after 5 minutes of caching
caches.add(new GuavaCache(CacheConfig.USER_CACHE,
CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build()));

simpleCacheManager.setCaches(caches);

return simpleCacheManager;
}

@Bean
public UserCache userCache() throws Exception {
Cache cache = cacheManager().getCache("userCache");
return new SpringCacheBasedUserCache(cache);
}


}
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
};

@Autowired
private UserRepository userRepository;

@Autowired
private UserCache userCache;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues())
.and()
.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.httpBasic();
}

@Override
@Bean
public UserDetailsService userDetailsService() {
UserService userService = new UserService(userRepository);
CachingUserDetailsService cachingUserService = new CachingUserDetailsService(userService);
cachingUserService.setUserCache(this.userCache);
return cachingUserService;
}

}
第一次调用效果很好,因为它调用了 UserRepository .但第二次,它没有调用存储库(如预期的那样),但我从 BCryptPasswordEncoder 收到以下警告:
2020-09-24 08:43:51.327  WARN 24624 --- [nio-8081-exec-4] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Empty encoded password
该警告的含义很明确,并且由于 null 而无法验证 de 用户。密码。但是我不明白为什么从缓存中重试的用户如果正确存储了空密码。我不确定如何使用缓存来解决它。有什么想法吗?
非常感谢您的帮助!

最佳答案

@M.Deinum 评论绝对正确。可以引用文档here .

Note that this implementation is not immutable. It implements theCredentialsContainer interface, in order to allow the password to beerased after authentication. This may cause side-effects if you arestoring instances in-memory and reusing them. If so, make sure youreturn a copy from your UserDetailsService each time it is invoked.


您可以查看 Spring-security source code如果你更好奇:
private boolean eraseCredentialsAfterAuthentication = true;

...

if (result != null) {
if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
}
// If the parent AuthenticationManager was attempted and successful then it
// will publish an AuthenticationSuccessEvent
// This check prevents a duplicate AuthenticationSuccessEvent if the parent
// AuthenticationManager already published it
if (parentResult == null) {
this.eventPublisher.publishAuthenticationSuccess(result);
}

return result;
}
User.java源代码:
@Override
public void eraseCredentials() {
this.password = null;
}
顺便说一句,以这种方式缓存登录用户看起来很奇怪。在登录期间,最好从数据库而不是从缓存中获取新记录。您可以在其他地方使用缓存用户,但很少看到它在登录期间使用。
如果您确实需要这样做,可以将默认标志更改为 falsedoc 中所述, 只需注入(inject) AuthenticationManager并调用:
setEraseCredentialsAfterAuthentication(false)

关于java - 使用 Spring Boot 缓存用户详细信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64045929/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com