0

私は、スプリングブート、スプリングセキュリティとスプリングデータを使用するWebアプリケーションを持っています。ステートレスです。SpringCacheBasedUserCache is null

私は、ユーザーアセスのための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); 
    } 
    ... 
} 

私はloadUserByUsername方法で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); 
    } 
    ... 
} 

を実装UserDetailsを実装し、別のクラスを持って、userCacheは(提案として)のいずれかがuserDetailsServiceBean法または上@Beanを置く

+1

あなたの 'UserServiceImpl'はスプリングマネージドBeanではないので、何も注入されません。次に、コードに欠陥があります。あなたがキャッシュに入れた 'user'は常に' null'です。 –

+1

自分でキャッシュするのではなく、自分の重大な作業を行う 'CachingUserDetailsS​​ervice'に自分の' UserDetailsS​​ervice'をラップするだけです。 –

答えて

2

nullの削除UserDetailsServiceから完全にキャッシングしてCachingUserDetailsServiceにラップし、代わりに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に委譲してユーザを取得します。

もちろん、キャッシングと混同されるのではなく、ユーザー管理/検索に専念することができる自分のUserDetailsServiceからキャッシュを削除する必要があります。

編集(1):コンストラクタは公開されていないため、Beanを作成するのが難しくなります。これは、BeanUtilsClassUtilsを使用して実現できます。 newへの呼び出しを次のものに置き換えると、インスタンスが作成されます。

private UserDetailsService cachingUserDetailsService(UserDetailsService delegate) { 
    Constructor<CachingUserDetailsService> ctor = ClassUtils.getConstructorIfAvailable(CachingUserDetailsService.class, UserDetailsService.class); 
    return BeanUtils.instantiateClass(ctor, delegate); 
} 

編集(2):は、どうやら私はすでに一度、すでに(約2年前に)これが発生し、それのためにthis issueを登録しました。

+0

CachingUserDetailsS​​ervice(UserDetailsS​​ervice)が公開されていません –

+0

コンストラクタが 'public'ではないことを忘れました。奇妙なことはxmlの設定はかなり簡単ですが、Javaベースの設定では、明らかに 'jdbcAuthentication'のために(簡単に)設定できるだけです。インスタンスを作成するために 'ClassUtils'を使って' BeanUtils'を使って回避することができます。 (変更された回答を参照)。 –

+0

OK、ユーザーがパスワードを変更した場合は、キャッシュのユーザーを削除する必要がありますか? –