SpringBoot之Zuul服务

概述

Spring Cloud Netflix zuul组件是微服务架构中的网关组件,其核心功能是路由和过滤,目前公司业务就是基于Zuul搭建的网关服务,本文主要内容:Zuul的执行流程、Zuul过滤实现、Zuul安全配置

Zuul服务

Zuul执行流程

  • 接收请求
    • 客户端发送请求到Zuul服务器(前置经过Nginx反向代理)
  • Pre-filters
    • 请求首先通过Pre类型的过滤器,这些过滤器可以进行安全检查、身份验证、日志记录、选择路由等操作。
  • 路由转发Routing
    • 如果Pre-filter通过请求将被路由到具体的微服务实例上。Zuul 可以根据配置的路由规则将请求转发到不同的后端服务。
  • 服务调用
    • Zuul通过Fegin进行客户端负载均衡,选择一个服务实例进行调用
  • Post-filters
    • 服务处理完成后,响应会返回并经过 Post 类型的过滤器,这些过滤器可以修改返回的响应头、收集统计信息等。最终Zuul将响应发送回客户端
  • Error-filters
    • 如果在任何阶段发生错误,请求将被转发到 Error 类型的过滤器,进行错误处理后经过Post-filters,最终Zuul将响应发送回客户端

Zuul过滤器

pre-filter

前置过滤器在请求被路由到源服务器之前执行,通常继承ZuulFilter抽象类。实际项目中我们使用前置过滤器对于400到500的状态错误码进行过滤,进而对于从cas认证服务中获取token的特定请求进行错误日志的记录

java 复制代码
package test.gateway.filter;

import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import test.common.util.R;
import com.google.gson.Gson;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

/**
 * @Description: 捕获400到500错误码,否则不执行该过滤器
 */
public class ErrorStatusCodeZuulFilter extends ZuulFilter {
	
	protected static String GET_TOKEN_URI =  "/cas/getToken";
	
    @Override
    public String filterType() {
        return "post";
    }

    @Override
    public int filterOrder() {
        return -1; // Needs to run before SendResponseFilter which has filterOrder == 0
    }

    @Override
    public boolean shouldFilter() {    		
    		int statusCode = Integer.parseInt(RequestContext.getCurrentContext().get("responseStatusCode").toString());
    		return statusCode >= 400 && statusCode <= 500;
    }

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		int statusCode = Integer.parseInt( ctx.get("responseStatusCode").toString());	
		String uri = ctx.get("requestURI").toString();
		if (uri != null && uri.equals(GET_TOKEN_URI)) { //获取token请求失败
			R<String>  res = new R<>();		
			res.setCode(statusCode);
			res.setData(null);
			res.setMsg("Account or password error");
			ctx.setResponseBody(new Gson().toJson(res));
			return null;
		}
		try {
			throw new Exception();
		} catch (Throwable t) {	    		
			throw new ZuulRuntimeException(new ZuulException(t, statusCode, t.getMessage()));
		}
	}
}
routing-filter

处理将请求发送到源服务器的逻辑

post-filter

后置过滤器在请求被路由后执行,可以对响应进行修改或添加额外的HTTP等。

error-filter

当请求处理过程中发生错误时,这些过滤器会被调用,同时最终也会调用后置post类型过滤器返回

扩展-OncePerRequestFilter

OncePerRequestFilter是Spring Framework中的一个接口,它属于Servlet过滤器(Filter)的范畴,但不是Zuul中定义的特定过滤器类型。在Spring MVC中,OncePerRequestFilter确保每个请求只被处理一次。它通过同步代码块来保证,即使在支持异步处理的 Spring MVC 应用程序中,请求也不会被重复处理。项目中我们通过自定义过滤器(继承OncePerRequestFilter)处理访问公共接口且未携带token的请求,该过滤器也属于前置的过滤器,因为它通常用于在请求进入其他阶段之前执行某些操作。

Zuul安全配置

自定义WebSecurityConfig

在Spring Security的上下文中,WebSecurityConfig类通常用于配置Spring Security的安全策略。此类继承自WebSecurityConfigurerAdapter,WebSecurityConfig可以用来定义Zuul网关的安全设置,通过提供了一种自定义安全配置的方法实现,实际项目中我们对zuul进行的http请求相关安全配置

java 复制代码
package test.zuul.config;
import ...

/**
 * @Description: Zuul http configuration
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 定义Zuul网关的安全设置
	private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
	
	@Autowired
    private FilterIgnorePropertiesConfig filterIgnorePropertiesConfig;
	
	@Autowired
	private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
	
	@Autowired
	private RedisOperationsSessionRepository redisOperationsSessionRepository; 
	
	@Autowired
	private AuthenticationServiceFeign authenticationService;
	
    @Override
    public void configure(HttpSecurity http) throws Exception {
    		http
    			.csrf()
    			.disable(); //禁用csrf
    		http
    			.headers()
    			.frameOptions()
    			.disable();
    		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry =
	    	http
	    		.antMatcher("/**") // 允许所有请求
		        .authorizeRequests();
			filterIgnorePropertiesConfig.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
			registry
		    	.anyRequest()
		        .authenticated();
		    http
		        .exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login/idpbg"))	        
		        .and()
		        .logout().logoutUrl("/logout").addLogoutHandler(new LogoutHandler() { //登出后处理逻辑
					@Override
					public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {					
						if(authentication != null) {
							String indexName = authentication.getName();
							// 查询用户的 Session 信息      
							Map<String, ? extends Session> userSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, indexName);
							
							// 删除当前用户相关session
							List<String> sessionIds = new ArrayList<>(userSessions.keySet());
							for (String session : sessionIds) {
								redisOperationsSessionRepository.deleteById(session);
							}
							//删除系统当前在线用户信息...
						}
						Cookie cookie = new Cookie();
						//重置cookie...
						response.addCookie(cookie);
					}
				}).logoutSuccessHandler(logoutSuccessHandler()).oauth2Login().and().oauth2Client();	
    }
    
    private LogoutSuccessHandler logoutSuccessHandler() { //登出成功后处理逻辑
		return new LogoutSuccessHandler() {
			@Override
			public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {
				if(authentication != null) {
					if(authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
						// 刪除JWT
						......
					}
				}
				new SecurityContextLogoutHandler().logout(request, null, null);
				try {
					response.sendRedirect("/"); //重定向到登录页面
					}
		        } catch (IOException e) {
		            e.printStackTrace();
		        }
			}
		};
	}
}
相关推荐
憧憬成为java架构高手的小白1 小时前
苍穹外卖--day09
java·spring boot·百度
Jasonakeke2 小时前
SpringBoot自动配置原理揭秘
java·spring boot·后端
ylscode2 小时前
Windows 内核惊现高危提权漏洞 CVE-2026-40369:沙箱隔离失效,SYSTEM 权限唾手可得
网络·安全·安全威胁分析
李子琪。2 小时前
网络空间安全深度实战:CSRF 漏洞原理剖析与基于 Token 的纵深防御体系构建(全栈实验报告)
前端·安全·csrf
Ramble_Naylor3 小时前
东方通(TongWeb)SpringBoot开发指导
java·spring boot
JacksonMx4 小时前
@Transactional 最佳实践
java·spring boot·spring·性能优化
黎阳之光5 小时前
数智透明·安全兜底|黎阳之光透明矿山,AI+数字孪生守护矿山生命线
人工智能·物联网·算法·安全·数字孪生
Xpower 175 小时前
MCP 服务器暴露在公网:AI Agent 工具层正在变成新的安全边界
服务器·人工智能·安全
2601_956456345 小时前
2026跨境多账号防封指南:四大指纹浏览器多维深度横测,哪款指纹浏览器适合推荐?
人工智能·安全
风落无尘5 小时前
第十一章《对齐与安全》 完整学习资料
python·安全·机器学习