您的位置:首页 > 数据库 > Redis

SpringBoot+redis 实现shiro集群,共享session。亲测可用

u3361262 2018-01-16 00:00 471 查看
1.序列化工具类:

import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;

/**
* redis序列化对象
*/
public class RedisObjectSerializer implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
static final byte[] EMPTY_ARRAY = new byte[0];

public Object deserialize(byte[] bytes) {
if (isEmpty(bytes)) {
return null;
}
try {
return deserializer.convert(bytes);
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}

public byte[] serialize(Object object) {
if (object == null) {
return EMPTY_ARRAY;
}
try {
return serializer.convert(object);
} catch (Exception ex) {
return EMPTY_ARRAY;
}
}

private boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
}

2.从redis读写session的类:RedisSessionDAO,实现共享session

/**
* redis实现共享session
*/
public class RedisSessionDAO extends EnterpriseCacheSessionDAO {

private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

// session 在redis过期时间是30分钟30*60
private static int expireTime = 1800;

private static String prefix = "shiro_redis_session:";

@Resource
private RedisTemplate<String, Object> redisTemplate;

public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

// 创建session,保存到数据库
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
logger.debug("创建session:{}", session.getId());
redisTemplate.opsForValue().set(prefix + sessionId.toString(), session);
return sessionId;
}

// 获取session
@Override
protected Session doReadSession(Serializable sessionId) {
logger.debug("获取session:{}", sessionId);
// 先从缓存中获取session,如果没有再去数据库中获取
Session session = super.doReadSession(sessionId);
if (session == null) {
session = (Session) redisTemplate.opsForValue().get(prefix + sessionId.toString());
}
return session;
}

// 更新session的最后一次访问时间
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
logger.debug("获取session:{}", session.getId());
String key = prefix + session.getId().toString();
if (!redisTemplate.hasKey(key)) {
redisTemplate.opsForValue().set(key, session);
}
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
}

// 删除session
@Override
protected void doDelete(Session session) {
logger.debug("删除session:{}", session.getId());
super.doDelete(session);
redisTemplate.delete(prefix + session.getId().toString());
}
}

3.RedisCacheManager,实现redis进行缓存管理:

import javax.annotation.Resource;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;

public class RedisCacheManager implements CacheManager {

@Resource
private RedisTemplate<String, Object> redisTemplate;

@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
return new ShiroCache<K, V>(name, redisTemplate);
}

public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}

public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

}

4.重写,配置缓存管理:ShiroCache<K, V>

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;

@SuppressWarnings("unchecked")
public class ShiroCache<K, V> implements Cache<K, V> {

private static final String REDIS_SHIRO_CACHE = "shiro_redis_session:";
private String cacheKey;
private RedisTemplate<K, V> redisTemplate;
private long globExpire = 30;

@SuppressWarnings("rawtypes")
public ShiroCache(String name, RedisTemplate client) {
//        this.cacheKey = REDIS_SHIRO_CACHE + name + ":";
this.cacheKey = REDIS_SHIRO_CACHE;
this.redisTemplate = client;
}

@Override
public V get(K key) throws CacheException {
redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES);
return redisTemplate.boundValueOps(getCacheKey(key)).get();
}

@Override
public V put(K key, V value) throws CacheException {
V old = get(key);
redisTemplate.boundValueOps(getCacheKey(key)).set(value);
return old;
}

@Override
public V remove(K key) throws CacheException {
V old = get(key);
redisTemplate.delete(getCacheKey(key));
return old;
}

@Override
public void clear() throws CacheException {
redisTemplate.delete(keys());
}

@Override
public int size() {
return keys().size();
}

@Override
public Set<K> keys() {
return redisTemplate.keys(getCacheKey("*"));
}

@Override
public Collection<V> values() {
Set<K> set = keys();
List<V> list = new ArrayList<>();
for (K s : set) {
list.add(get(s));
}
return list;
}

private K getCacheKey(Object k) {
return (K) (this.cacheKey + k);
}
}

5.配置redisConfig:

import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.vcooc.experiment.utils.RedisObjectSerializer;
/**
* redis配置
* @author Administrator
*
*/
@Configuration
public class RedisConfig {

@Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(1800);
return cacheManager;
}

//TODO
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer());
return template;
}
}

6.配置shiroConfig:

import java.util.HashMap;
import java.util.Map;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import com.vcooc.experiment.shiro.RedisCacheManager;
import com.vcooc.experiment.shiro.RedisSessionDAO;

/**
*
* @author April.Chen
*/
@Configuration
public class ShiroConfig {

/* @Bean
public UserRealm getUserRealm() {
return new UserRealm();
}*/

@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}

@Bean
public RedisCacheManager redisCacheManager() {
return new RedisCacheManager();
}

@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisTemplate(new RedisTemplate<String,Object>());
return redisSessionDAO;
}

@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setGlobalSessionTimeout(1800);
sessionManager.setCacheManager(redisCacheManager());
sessionManager.getSessionIdCookie().setName("vcoocUserId");
return sessionManager;
}

@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}

@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager());
return new AuthorizationAttributeSourceAdvisor();
}

@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}

@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
Map<String, String> filterChainDefinitionMap = new HashMap<>();
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
//放行静态资源
filterChainDefinitionMap.put("/static/**", "anon");
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setSuccessUrl("/index");
filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}

配置redis 的property:

redis:
host: 127.0.0.1
port: 6379

以上转自另外一个帖子,原帖我直接复制不可用,稍作修改,可以运行了,上面是我修改后的。
标签:  Redis Spring Boot Shiro