SpringSecurity 禁用使用者後 實現清除指定使用者快取
阿新 • • 發佈:2019-02-16
問題出現的場景:
一般在類似於資訊管理平臺,通常會有對使用者的狀態進行操作,我遇到的問題是,當管理員使用者,禁用普通使用者後,普通使用者仍然可以登入。
出現的原因:
SpringSecurity在使用者登陸訪問系統過程中,會將使用者的登陸資訊儲存到cache當中,它允許將頻繁訪問的伺服器資源儲存在記憶體中,當用戶發出相同的請求後,伺服器不是再次處理而是將Cache中儲存的資料直接返回給使用者。因此,當管理員進行使用者禁用時,如果不及時重新整理快取,使用者再次登陸,依舊可以登入成功。
解決
實現思路:當管理員操作普通使用者時,清除指定使用者快取。
程式碼如下:
@Autowired
private ICacheRefreshService cacheRefreshService;
......
//將使用者鎖定
if (type == 1) {
userLock.setStatus("1");
userService.update(userLock);
//實現重新整理使用者快取
this.cacheRefreshService.refreshUser(userName);
//記錄操作日誌
logService.sysLog(Log.SYSTEM, "使用者-鎖定", userLock.getId(), userLock.getUserName()+ "|"+userLock.getRealName(), "鎖定使用者");
//頁面處理,和文章無關
result = new Result(true, "使用者鎖定成功!");
}
建立工具類
//interface
public interface ICacheRefreshService {
public void refreshUrl();
public void refreshUser(String username);
}
//實現類
public class CacheRefreshService implements ICacheRefreshService {
private UserCache userCache;//使用者快取
private IResourceCacheManager urlCache;//資源授權快取(和本篇內容無關)
/**
* 重新整理其中一個使用者
* @param username
*/
public void refreshUser(String username){
userCache.removeUserFromCache(username);
}
/**
* 重新整理全部URL
*/
public void refreshUrl(){
urlCache.removeAll();
urlCache.init();
}
public void setUserCache(UserCache userCache) {
this.userCache = userCache;
}
public void setUrlCache(IResourceCacheManager urlCache) {
this.urlCache = urlCache;
}
}
//interface UserCache
public interface UserCache {
/**
* Obtains a {@link UserDetails} from the cache.
*
* @param username the {@link User#getUsername()} used to place the user in the cache
*
* @return the populated <code>UserDetails</code> or <code>null</code> if the user could not be found or if the
* cache entry has expired
*/
UserDetails getUserFromCache(String username);
/**
* Places a {@link UserDetails} in the cache. The <code>username</code> is the key used to subsequently
* retrieve the <code>UserDetails</code>.
*
* @param user the fully populated <code>UserDetails</code> to place in the cache
*/
void putUserInCache(UserDetails user);
/**
* Removes the specified user from the cache. The <code>username</code> is the key used to remove the user.
* If the user is not found, the method should simply return (not thrown an exception).<P>Some cache
* implementations may not support eviction from the cache, in which case they should provide appropriate
* behaviour to alter the user in either its documentation, via an exception, or through a log message.</p>
*
* @param username to be evicted from the cache
*/
void removeUserFromCache(String username);
}
//EhCacheBasedUserCache
/**
* Caches <code>User</code> objects using a Spring IoC defined <A
* HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
*
* @author Ben Alex
* @version $Id: EhCacheBasedUserCache.java 2217 2007-10-27 00:45:30Z luke_t $
*/
public class EhCacheBasedUserCache implements UserCache, InitializingBean {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(EhCacheBasedUserCache.class);
//~ Instance fields ================================================================================================
private Ehcache cache;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "cache mandatory");
}
public Ehcache getCache() {
return cache;
}
public UserDetails getUserFromCache(String username) {
Element element = null;
try {
element = cache.get(username);
} catch (CacheException cacheException) {
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
}
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; username: " + username);
}
if (element == null) {
return null;
} else {
return (UserDetails) element.getValue();
}
}
public void putUserInCache(UserDetails user) {
Element element = new Element(user.getUsername(), user);
if (logger.isDebugEnabled()) {
logger.debug("Cache put: " + element.getKey());
}
cache.put(element);
}
public void removeUserFromCache(UserDetails user) {
if (logger.isDebugEnabled()) {
logger.debug("Cache remove: " + user.getUsername());
}
this.removeUserFromCache(user.getUsername());
}
public void removeUserFromCache(String username) {
cache.remove(username);
}
public void setCache(Ehcache cache) {
this.cache = cache;
}
}
springSecurity配置的部分程式碼:
<!--cache manager-->
<beans:bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml">
</beans:bean>
<beans:bean id="userCache"
class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache">
<beans:property name="cache">
<beans:bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"
p:cacheManager-ref="cacheManager"
p:cacheName="security.user"/>
</beans:property>
</beans:bean>
<beans:bean id="urlCache"
class="org.zcframework.security.cache.impl.UrlResourceCacheManager" init-method="init"
destroy-method="destroy">
<beans:property name="cache">
<beans:bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"
p:cacheManager-ref="cacheManager"
p:cacheName="security.url"/>
</beans:property>
<beans:property name="resourceDetailService" ref="resourceDetailService"/>
</beans:bean>
<beans:bean id="cacheRefreshService" class="org.zcframework.security.cache.impl.CacheRefreshService">
<beans:property name="userCache" ref="userCache"/>
<beans:property name="urlCache" ref="urlCache"/>
</beans:bean>