本文主要介绍下,SpringBoot的web项目中,java
使用redis保存并共享session,能够实现集群内的登陆信息共享。SpringBoot项目中,经过在application.yml
增长redis的配置,便可实现对session的存储和修改。web
那么session是在什么时候被处理的?session的key又是如何生成的呢?这里实际使用了web项目中的过滤器。redis
在SpringBoot的web项目中,启动的tomcat在处理http请求时,有一个很重要的类:ApplicationFilterChain
。每一个http请求在处理时都会经过这个类。这个类负责按顺序处理所有已注册的Filter
,也就是过滤器。经过实现tomcat中的Filter
接口,就能够定义一个过滤器。json
在SpringBoot中的web项目中,有几个默认的过滤器,其中一个就是用来处理session的:SessionRepositoryFilter
tomcat
SessionRepositoryFilter
主要的成员是两个接口,都有多个可选的实现类,经过这两个成员就实现了对session的解析。cookie
SessionRepository
session
RedisIndexedSessionRepository
HttpSessionIdResolver
app
CookieHttpSessionIdResolver
,能够看出是从cookie中解析。HeaderHttpSessionIdResolver
,由此能够看出还能够将sessionid保存在header中。固然也能够实现一个本身的过滤器,主要有两种方式:ide
实现Filter
接口,并使用@WebFilter
注解学习
OncePerRequestFilter
这个类,这个类也是Filter
接口的实现类,封装了一些功能,使用更方便。FilterRegistrationBean
的对象。下面咱们使用第一种方式实现一个限制指定IP的过滤器:
/** * ip黑名单 */ @WebFilter public class IPFilter extends OncePerRequestFilter { //这里继承OncePerRequestFilter private List<String> forbiddenIpList = new ArrayList<>(); public IPFilter() { this.forbiddenIpList.add("10.112.13.167"); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String ip = request.getRemoteAddr(); if (this.forbiddenIpList.contains(ip)) { response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); ObjectMapper objectMapper = new ObjectMapper(); out.write(objectMapper.writeValueAsString(CommonResVo.fail(400, "禁止访问的ip"))); out.flush(); } else { filterChain.doFilter(request, response); } } }
经过过滤器解析session后,就能够根据session中保存的内容,判断当前登陆的用户权限。
这里是经过一个拦截器实现的,在拦截器中能够直接经过HttpServletRequest.getSession()
方法直接获取session的信息。
一个简单的拦截器实现以下:
@Component public class LoginAuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Integer userId = (Integer) session.getAttribute("userId"); if (userId == null) { authFailOutput(response, "登陆信息不存在,请从新登陆"); return false; } return true; } /** * json输出 */ private void authFailOutput(HttpServletResponse response, String msg) throws IOException { response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); ObjectMapper objectMapper = new ObjectMapper(); out.write(objectMapper.writeValueAsString(CommonResVo.fail(400, msg))); out.flush(); } }
定义以后要注册处处理流程中:
@Configuration public class Interceptor implements WebMvcConfigurer { @Resource HandlerInterceptor loginAuthInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 添加一个拦截器,判断权限,排除掉登陆接口 registry.addInterceptor(loginAuthInterceptor) .excludePathPatterns("/user/login","/user/register"); } }
先来看下过滤器和拦截器的执行顺序,经过debug获得的执行顺序以下图:
在大部分场景中,过滤器和拦截器都是可互换的,使用哪一个均可以。
过滤器和拦截器也有些区别,这里不谈实现和规范的差别,就说下使用中可能涉及的区别:
最后对于过滤器和拦截器的应用场景,说下我的的总结。基于执行顺序,方法参数和SpringBoot中的一些实现类来看。
以上内容属我的学习总结,若有不当之处,欢迎在评论中指正