一、前言
一下代码以SSO用户登录列子代码。完整代码https://gitee.com/xuxueli0323/xxl-sso
二、使用
2.1 创建过滤器
创建一个过滤器,实现Filter 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | public class XxlSsoTokenFilter extends HttpServlet implements Filter { private static Logger logger = LoggerFactory.getLogger(XxlSsoTokenFilter. class ); private static final AntPathMatcher antPathMatcher = new AntPathMatcher(); private String ssoServer; private String logoutPath; private String excludedPaths; @Override public void init(FilterConfig filterConfig) throws ServletException { ssoServer = filterConfig.getInitParameter(Conf.SSO_SERVER); logoutPath = filterConfig.getInitParameter(Conf.SSO_LOGOUT_PATH); excludedPaths = filterConfig.getInitParameter(Conf.SSO_EXCLUDED_PATHS); logger.info( "XxlSsoTokenFilter init." ); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // make url String servletPath = req.getServletPath(); // excluded path check if (excludedPaths!= null && excludedPaths.trim().length()> 0 ) { for (String excludedPath:excludedPaths.split( "," )) { String uriPattern = excludedPath.trim(); // 支持ANT表达式 if (antPathMatcher.match(uriPattern, servletPath)) { // excluded path, allow chain.doFilter(request, response); return ; } } } // logout filter if (logoutPath!= null && logoutPath.trim().length()> 0 && logoutPath.equals(servletPath)) { // logout SsoTokenLoginHelper.logout(req); // response res.setStatus(HttpServletResponse.SC_OK); res.setContentType( "application/json;charset=UTF-8" ); res.getWriter().println( "{\"code\":" +ReturnT.SUCCESS_CODE+ ", \"msg\":\"\"}" ); return ; } // login filter XxlSsoUser xxlUser = SsoTokenLoginHelper.loginCheck(req); if (xxlUser == null ) { // response res.setStatus(HttpServletResponse.SC_OK); res.setContentType( "application/json;charset=UTF-8" ); res.getWriter().println( "{\"code\":" +Conf.SSO_LOGIN_FAIL_RESULT.getCode()+ ", \"msg\":\"" + Conf.SSO_LOGIN_FAIL_RESULT.getMsg() + "\"}" ); return ; } // ser sso user request.setAttribute(Conf.SSO_USER, xxlUser); // already login, allow chain.doFilter(request, response); return ; } } |
2.2 注册filter
使用java 配置 @Configuration 注解配置 ,通过FilterRegistrationBean ,向spring容器中注入 过滤器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @Configuration public class XxlSsoConfig implements DisposableBean { @Value ( "${xxl.sso.server}" ) private String xxlSsoServer; @Value ( "${xxl.sso.logout.path}" ) private String xxlSsoLogoutPath; @Value ( "${xxl.sso.redis.address}" ) private String xxlSsoRedisAddress; @Value ( "${xxl-sso.excluded.paths}" ) private String xxlSsoExcludedPaths; @Bean public FilterRegistrationBean xxlSsoFilterRegistration() { // xxl-sso, redis init JedisUtil.init(xxlSsoRedisAddress); // xxl-sso, filter init FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setName( "XxlSsoWebFilter" ); registration.setOrder( 1 ); registration.addUrlPatterns( "/*" ); registration.setFilter( new XxlSsoTokenFilter()); registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer); registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath); registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths); return registration; } @Override public void destroy() throws Exception { // xxl-sso, redis close JedisUtil.close(); } } |
三、执行流程
以springboot 为列子,看filter 是如何工作的
3.1 bean的注入
因为filter 以 FilterRegistrationBean 的形式 注入到spring 的容器,首先来看看这个类的结构 ,可以看到这个类实现 ServletContextInitializer 接口
3.2 断点跟踪
在FilterRegistrationBean 类中有个方法getFilter 获取的过滤器,在这里打个断点,看看spring在什么时候会来获取过滤器。
启动容器,进入断点 ,观察栈信息,可以看到是在创建spring容器后创建tomcat 服务进入的断点
然后拿到所有接口实现,调用
看下 FilterRegistrationBean 调用 onStartup 把filter获取注册到servletContext 容器中
最后 封装成 FilterMap放进org.apache.catalina.core.StandardContext#filterMaps
3.3 前端断点
在过滤器中打上断点,前端发起请求,进入断点
找到 ApplicationFilterChain 看到过滤器在 org.apache.catalina.core.ApplicationFilterChain#filters 中 ,分析发现添加过滤器的方法 ,在此方法设置断点,前端再次发请求
过滤器链创建完了之后 会调用 过滤器链,用里面的过滤器循环过滤
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端