本文主要是介绍替换Servlet容器的HttpSession实现集群中Session共享(With Redis),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文是我个人在开发web-security 安全框架中使用的方案。
在Web Server集群环境中需要实现 session 共享,一个很好的方法就是将 session 数据存放至 Redis 中。我打算在自己的安全框架中集成此功能,只需要几行配置就能自动让你的 web 项目集成 redis session 共享功能。
实现思路为:
将 Servlet 容器的HttpSession
实现替换成自己的实现, 如RedisHttpSession
。这样当在Controlelr
中调用session.setAttr()
此类方法时就可以执行自己的代码。我们编写一个Filter
, 在调用chain.doFilter(req, resp)
时,将HttpServletRequest
对象替换成我们自定义的SecurityServletRequestWrapper
对象,并重写getSession()
和getSession(boolean)
方法,让其返回我们自己的session对象,这样就完成了对session的完全控制 。
替换 Servlet 容器的 HttpSession 实现
首选需要编写SecurityServletRequestWrapper
类:
public class SecurityServletRequestWrapper extends HttpServletRequestWrapper {private static Logger log = LoggerFactory.getLogger(SecurityServletRequestWrapper.class);private HttpSession session;public SecurityServletRequestWrapper(HttpServletRequest request, HttpSession session) {super(request);if (null != session) {this.session = session;}}@Overridepublic HttpSession getSession() {log.debug("getSession() invoked!");return getSession(true);}/*** 返回自定义的HttpSession实现* @param create* @return*/@Overridepublic HttpSession getSession(boolean create) {log.debug("getSession(boolean) invoked!");if (create && null == session) {log.debug("creating new Session object!");session = new NativeHttpSession(getServletContext());}return session;}
}
然后,编写一个filter, 用我们刚刚完成的SecurityHttpServetRequest
替换掉doFilter()
方法中的第一个参数,代码大致如下:
/*** 遍历filters, 依次执行每一个过虑器*/@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;// 将request对象替换成自定义的wrapper对象req = new SecurityServletRequestWrapper(req, session);chain.doFilter(req, response);}
我们必须保证在请求到来时,该过滤器第一个被调用,请求完成后,该过虑器最后被调用。这样我们便可以在chain.doFilter()
之前 添加从 Redis 中读取 session的代码,在chain.doFilter()
之后添加刷新 session 至 redis 的代码:
@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;// 如果开启了session cluster// 执行session cluster相关逻辑if (PageProtectionContextListener.SESSION_CLUSTER) {// 尝试从存储仓库中查询sessionHttpSession session = sessionDAO.loadSession(getSid(req));logger.debug("session loaded, result => {}", session);// 将request对象替换成自定义的wrapper对象req = new SecurityServletRequestWrapper(req, session);}chain.doFilter(req, response);// 执行session cluster相关逻辑if (PageProtectionContextListener.SESSION_CLUSTER) {// 刷新session数据// 先判断有无sessionHttpSession session = req.getSession(false);// 如果没有session, 不做任何处理if (null == session) {return;}if (false == session instanceof NativeHttpSession) {throw new UnsupportedFilterException("filter " + session.getClass() + " unsupported!");}NativeHttpSession nativeSession = (NativeHttpSession) session;if (nativeSession.isDirty()) {logger.debug("flushing session");sessionDAO.flushSession(nativeSession);}}}
以上是整体实现思路和关键代码的实现,我们可以在此基础上,根据实际需求添加自己系统需要的功能。
这篇关于替换Servlet容器的HttpSession实现集群中Session共享(With Redis)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!