有个后端项目需要添加一台服务器做均衡。框架用到了springMvc,shiro作为登录和权限控制,发现用spring-session做session有点问题,具体不在描 参考作者忘记了-.-!
1.application.xml shiro配置
<bean id="collectionRedisSessionDao" class="com.fh.dao.CollectionRedisSessionDao"></bean>
<!-- session管理器 -->
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 超时时间 -->
<property name="globalSessionTimeout" value="7200000" />
<!-- session存储的实现 -->
<property name="sessionDAO" ref="collectionRedisSessionDao"></property>
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<property name="sessionIdCookie" ref="sharesession" />
<!-- 定时检查失效的session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
</bean>
<bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- cookie的name,对应的默认是 JSESSIONID -->
<constructor-arg name="name" value="SHAREJSESSIONID"/>
<!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
<property name="path" value="/"/>
</bean>
<!-- ================ Shiro start ================ -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="ShiroRealm" />
<property name="sessionManager" ref="sessionManager"></property>
</bean>
<!-- 項目自定义的Realm -->
<bean id="ShiroRealm" class="com.fh.interceptor.shiro.ShiroRealm" ></bean>
<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/" />
<property name="successUrl" value="/main/index" />
<property name="unauthorizedUrl" value="/login_toLogin" />
<property name="filterChainDefinitions">
<value>
/static/login/** = anon
/static/** = anon
/plugins/** = anon
/static/js/** = anon
/uploadFiles/uploadImgs/** = anon
/upload/** = anon
/code.do = anon
/login_login = anon
/app**/** = anon
/weixin/** = anon
/** = authc
</value>
</property>
</bean>
2.web.xml
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.java代码
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@SuppressWarnings({"rawtypes","unchecked"})
@Component("collectionRedisSessionDao")
@Lazy(false)
public class CollectionRedisSessionDao extends AbstractSessionDAO {
private static Logger logger = LoggerFactory.getLogger(CollectionRedisSessionDao.class);
@Autowired
private RedisTemplate redisTemplate;
// @Value("${redis.key.prefix}")
private String redisPrefixKey="redisPrefixKey";
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:";
private String getKey(String originalKey) {
return redisPrefixKey + keyPrefix+originalKey;
}
@PostConstruct
public void init(){
logger.info("注入催收的序列/反序列类");
CollectionSerializer<Serializable> collectionSerializer=CollectionSerializer.getInstance();
redisTemplate.setDefaultSerializer(collectionSerializer);
//redisTemplate默认采用的其实是valueSerializer,就算是采用其他ops也一样,这是一个坑。
redisTemplate.setValueSerializer(collectionSerializer);
}
@Override
public void update(Session session) throws UnknownSessionException {
logger.debug("更新seesion,id=[{}]", session.getId().toString());
try {
redisTemplate.opsForValue().set(getKey(session.getId().toString()), session,30,TimeUnit.MINUTES);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
}
@Override
public void delete(Session session) {
logger.debug("删除seesion,id=[{}]", session.getId().toString());
try {
String key=getKey(session.getId().toString());
redisTemplate.delete(key);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
}
@Override
public Collection<Session> getActiveSessions() {
logger.info("获取存活的session");
return Collections.emptySet();
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = generateSessionId(session);
assignSessionId(session, sessionId);
logger.debug("创建seesion,id=[{}]", session.getId().toString());
try {
redisTemplate.opsForValue().set(getKey(session.getId().toString()), session,30,TimeUnit.MINUTES);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
logger.debug("获取seesion,id=[{}]", sessionId.toString());
Session readSession = null;
try {
readSession=(Session) redisTemplate.opsForValue().get(getKey(sessionId.toString()));
} catch (Exception e) {
logger.error(e.getMessage());
}
return readSession;
}
}
import org.apache.commons.lang3.SerializationUtils;
import java.io.Serializable;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
public class CollectionSerializer<T extends Serializable> implements RedisSerializer<T>{
private CollectionSerializer(){}
public static volatile CollectionSerializer<Serializable> collectionSerializer=null;
public static CollectionSerializer<Serializable> getInstance(){
if(collectionSerializer==null){
synchronized (CollectionSerializer.class) {
if(collectionSerializer==null){
collectionSerializer=new CollectionSerializer<>();
}
}
}
return collectionSerializer;
}
@Override
public byte[] serialize(T t) throws SerializationException {
return SerializationUtils.serialize(t);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
return SerializationUtils.deserialize(bytes);
}
}