Zuul的大部分功能都是基于Filter过滤器的,这个Filter不是我们Web开发中Servlet的Filter,而是Zuul自己的Filter,但其功能类似于Servlet框架的Filter。
1、创建项目zuul网关
依赖为:
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency></dependencies>
application.yml配置:
server:port: 80spring:application:name: crowd-zuuleureka:client:service-url:defaultZone: http://localhost:1000/eurekazuul:ignored-services: "*"sensitive-headers: "*" # 在Zuul向其他微服务重定向时保持原本头信息(请求头、响应头)routes:crowd-portal:service-id: crowd-authpath: /** # 这里一定要使用两个“*”号,不然“/”路径后面的多层路径将无法访问ribbon:ReadTimeout: 10000ConnectTimeout: 10000
启动类:
@EnableZuulProxy // 开启zuul代理模式@SpringBootApplicationpublic class CrowdMainClass {public static void main(String[] args) {SpringApplication.run(CrowdMainClass.class, args);}}
ZuulFilter类
@Componentpublic class CrowdAccessFilter extends ZuulFilter {@Overridepublic boolean shouldFilter() {// 1.获取RequestContext对象RequestContext requestContext = RequestContext.getCurrentContext();// 2.通过RequestContext对象获取当前请求对象(框架底层是借助ThreadLocal从当前线程上获取事先绑定的Request对象)HttpServletRequest request = requestContext.getRequest();// 3.获取servletPath值String servletPath = request.getServletPath();// 4.根据servletPath判断当前请求是否对应可以直接放行的特定功能boolean containsResult = AccessPassResources.PASS_RES_SET.contains(servletPath);if (containsResult) {// 5.如果当前请求是可以直接放行的特定功能请求则返回false放行return false;}// 5.判断当前请求是否为静态资源// 工具方法返回true:说明当前请求是静态资源请求,取反为false表示放行不做登录检查// 工具方法返回false:说明当前请求不是可以放行的特定请求也不是静态资源,取反为true表示需要做登录检查return !AccessPassResources.judgeCurrentServletPathWetherStaticResource(servletPath);}@Overridepublic Object run() throws ZuulException {// 1.获取当前请求对象RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();// 2.获取当前Session对象HttpSession session = request.getSession();// 3.尝试从Session对象中获取已登录的用户Object loginMember = session.getAttribute("userName");// 4.判断loginMember是否为空if(loginMember == null) {// 5.从requestContext对象中获取Response对象HttpServletResponse response = requestContext.getResponse();// 6.将提示消息存入Session域session.setAttribute("message", "请登录以后再访问!");// 7.重定向到auth-consumer工程中的登录页面try {response.sendRedirect("/auth/member/to/login/page");} catch (IOException e) {e.printStackTrace();}}return null;}@Overridepublic String filterType() {// 这里返回“pre”意思是在目标微服务前执行过滤return "pre";}@Overridepublic int filterOrder() {return 0;}}
AccessPassResourcesl类:
public class AccessPassResources {public static final Set<String> PASS_RES_SET = new HashSet<>();static {PASS_RES_SET.add("/");PASS_RES_SET.add("/auth/member/to/reg/page");PASS_RES_SET.add("/auth/member/to/login/page");PASS_RES_SET.add("/auth/member/logout");PASS_RES_SET.add("/auth/member/do/login");PASS_RES_SET.add("/auth/do/member/register");PASS_RES_SET.add("/auth/member/send/short/message.json");}public static final Set<String> STATIC_RES_SET = new HashSet<>();static {STATIC_RES_SET.add("bootstrap");STATIC_RES_SET.add("css");STATIC_RES_SET.add("fonts");STATIC_RES_SET.add("img");STATIC_RES_SET.add("jquery");STATIC_RES_SET.add("layer");STATIC_RES_SET.add("script");STATIC_RES_SET.add("ztree");}/*** 用于判断某个ServletPath值是否对应一个静态资源* @param servletPath* @return* true:是静态资源* false:不是静态资源*/public static boolean judgeCurrentServletPathWetherStaticResource(String servletPath) {// 1.排除字符串无效的情况if(servletPath == null || servletPath.length() == 0) {throw new RuntimeException("字符串不合法!请不要传入空字符串!");}// 2.根据“/”拆分ServletPath字符串String[] split = servletPath.split("/");// 3.考虑到第一个斜杠左边经过拆分后得到一个空字符串是数组的第一个元素,所以需要使用下标1取第二个元素String firstLevelPath = split[1];// 4.判断是否在集合中return STATIC_RES_SET.contains(firstLevelPath);}
当其他在eureka上的项目访问资源时,除静态资源,登录,注册请求外都会检查用户是否登录,没有登录则跳转到登录页面,提示用户登录以后再访问。