SpringCacheBasedUserCache为null

时间:2016-11-23 13:41:35

标签: spring spring-security spring-boot spring-data spring-cache

我有使用弹簧靴,弹簧安全和弹簧数据的web应用程序。它是无国籍的。

我想避免总是为用户访问调用db。所以我想使用SpringCacheBasedUserCache。

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("city"), new ConcurrentMapCache("userCache")));
        return cacheManager;
    }

    @Bean
    public UserCache userCache() throws Exception {

        Cache cache = (Cache) cacheManager().getCache("userCache");
        return new SpringCacheBasedUserCache(cache);
    }
}


@EnableCaching
@Configuration
@EnableWebSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository);
    }
    ...
}

我有一个实现UserDetails的类和另一个实现UserDetailsS​​ervice的类

@Service
public class UserServiceImpl implements UserDetailsService, UserService {

    private final CommerceRepository commerceReposiotry;
    private final UserAppRepository repository;
    private final DefaultConfigRepository defaultConfigRepository;

    @Autowired
    private UserCache userCache;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserServiceImpl(final CommerceRepository commerceReposiotry, final UserAppRepository repository, final DefaultConfigRepository defaultConfigRepository) {
        this.commerceReposiotry = commerceReposiotry;
        this.repository = repository;
        this.defaultConfigRepository = defaultConfigRepository;
    }


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

        UserDetails user = userCache.getUserFromCache(username);
        UserApp userapp = null;

        if (user == null) {
            userapp = repository.findByUsername(username);
        }

        if (userapp == null) {
            throw new UsernameNotFoundException("Username " + username + " not found");
        }

        userCache.putUserInCache(user);

        return new CustomUserDetails(userapp);
    }
    ...
}

在loadUserByUsername方法中,userCache为null

1 个答案:

答案 0 :(得分:2)

@Bean放在userDetailsServiceBean方法上或(根据建议)从您的UserDetailsService中完全删除缓存并将其包装在CachingUserDetailsService中,而只是覆盖{{而不是1}}方法。

userDetailsService

您的其他配置已经有@Configuration @EnableWebSecurity public class ApplicationSecurity extends WebSecurityConfigurerAdapter { @Autowired private UserCache userCache; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public UserDetailsService userDetailsService() throws Exception { UserServiceImpl userService = new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository); CachingUserDetailsService cachingUserService = new CachingUserDetailsService(userService); cachingUserService.setUserCache(this.userCache); return cachingUserService; } ... } ,因此无需再次使用。只需将缓存注入配置类并构造@EnableCaching,委托给CachingUserDetailsService以检索用户。

当然,您必须从自己的UserDetailsService中删除缓存,现在可以将注意力集中在用户管理/检索上,而不是与缓存混合。

编辑(1):构造函数不公开,使得创建bean变得更加困难。这可以使用UserDetailsServiceBeanUtils来实现。用以下内容替换对ClassUtils的调用应该创建一个实例。

new

编辑(2):显然我已经遇到过这个问题(大约2年前)并注册了this issue