摘要
在使用SpringMVC的时候,我们习惯使用与容器(tomcat)相关的session,不利于扩展。Shiro提供一整套的session解决方案,我们可以稍作修改就可以满足我们各种需求。
先看下我们的基本用法:
@RequestMapping("/index")
public ModelAndView index(HttpSession session){
System.out.println(session.getId());
ModelAndView modelAndView = new ModelAndView("main/index");
return modelAndView;
}
如果我们添加断点进行调试,可以看到session类型是:
org.apache.catalina.session.StandardSessionFacade
依赖于tomcat容器。
Shiro是一款非常优秀的用户-角色-权限管理框架,具体可以Google下。当然,Shiro也提供Session管理模块,现在我们就使用shiro+spring实现一个与容器无关的session。
引入shiro的jar包
<properties>
<shiroVersion>1.2.3</shiroVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiroVersion}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiroVersion}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiroVersion}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiroVersion}</version>
</dependency>
</dependencies>
配置shiro(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>*.html</url-pattern>
</filter-mapping>
配置shiro(spring)
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="sessionManager" ref="sessionManager"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
</bean>
<bean id="sessionManager" class="com.whereta.model.DemoSessionManager">
<property name="globalSessionTimeout" value="1000" />
<property name="deleteInvalidSessions" value="true" />
<property name="sessionValidationSchedulerEnabled" value="false" />
<property name="sessionDAO" ref="sessionDao" />
</bean>
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
<bean id="demoCache" class="com.whereta.model.DemoCache" />
<bean id="sessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="sessionIdGenerator" ref="sessionIdGenerator" />
<property name="activeSessionsCache" ref="demoCache"/>
</bean>
具体类用法
package com.whereta.model;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.session.Session;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 该类是缓存工具类,提供session的存储和获取等方法
* @author Vincent
* @time 2015/7/27 15:00
*/
public class DemoCache implements Cache<Serializable, Session> {
//模拟缓存存储session对象
private static final Map<Serializable, Session> map = new HashMap<Serializable, Session>();
public Session get(Serializable key) throws CacheException {
//根据key获取缓存中的session
return map.get(key);
}
public Session put(Serializable key, Session value) throws CacheException {
//将session对象存入缓存
map.put(key, value);
return value;
}
public Session remove(Serializable key) throws CacheException {
//移除session中为key的对象
Session session = get(key);
if (session != null) {
session.setAttribute(key, null);
return session;
}
return null;
}
public void clear() throws CacheException {
//清除所有的session
map.clear();
}
public int size() {
//返回session的数量
return map.size();
}
public Set<Serializable> keys() {
//返回所有session的key
return map.keySet();
}
public Collection<Session> values() {
//返回所有session
return map.values();
}
}
package com.whereta.model;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import java.io.Serializable;
/**
* sessionId生成工具类
* @author Vincent
* @time 2015/7/27 11:45
*/
public class DemoSessionIdGenerator implements SessionIdGenerator {
public Serializable generateId(Session session) {
//自定义规则生成sessionid
return System.currentTimeMillis();
}
}
package com.whereta.model;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* 集成websession管理器,重写两个方法实现自己的需求
* @author Vincent
* @time 2015/7/27 15:35
*/
public class DemoSessionManager extends DefaultWebSessionManager {
//自定义缓存,存储 客户端-sessionid
public static final Map<String,Serializable> MAP=new HashMap<String, Serializable>();
private static Log log = LogFactory.getLog(DemoSessionManager.class);
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
HttpServletRequest req= (HttpServletRequest) request;
//假设以请求地址为key标注唯一一个客户端
String remoteHost = req.getRemoteHost();
//存入缓存
Serializable id = MAP.get(remoteHost);
return id;
}
@Override
protected void onStart(Session session, SessionContext context) {
//判断是否是http请求
if (!WebUtils.isHttp(context)) {
log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +
"pair. No session ID cookie will be set.");
return;
}
HttpServletRequest request = WebUtils.getHttpRequest(context);
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
String remoteHost = request.getRemoteHost();
Serializable id = session.getId();
MAP.put(remoteHost,id);
}
}
通过以上配置,可以再次运行查看session,已经变为shiro的自定义session了
org.apache.shiro.web.servlet.ShiroHttpSession
|