本文主要介紹下,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中的一些實現類來看。
以上內容屬我的學習總結,若有不當之處,歡迎在評論中指正