SpringCloud实践专栏——网关Zuul

代码已上传至github:

1. 网关Zuul的简介

什么是Zuul?

我们已知,开启整个微服务工程项目的时候,都会在发送http请求的时候,通过一个路由的选择来到达指定的module,而网关的作用就是

在这里插入图片描述

为什么需要微服务网关

不同的微服务都有不同的网络地址,而外部的客户端需要调用多个服务的接口才能完成一个业务需求,比如一个sso,我们需要sso server的login给我们/oauth/token,sso client的redirect,token的解析,而且client是很多很多的,这就很难受,我们假设这里有1个sso-server,n个sso-client

会存在以下问题:

  1. 客户端多次请求不同的微服务,会很复杂
  2. cors的时候,也很复杂
  3. Authorization的时候,每一步都需要做配置

所以我们就可以依靠网关来解决这个问题了:

首先先导入依赖:

	<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

然后配置

server:
  port: 9012
spring:
  application:
    name: tensquare-manager
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka/
  instance:
    prefer-ip-address: true
zuul:
  routes:
    tensquare-base:
      path: /base/**
      serviceId: tensquare-base
    tensquare_friend:
      path: /article/**
      serviceId: tensquare_friend
    tensquare_gathering:
      path: /gathering/**
      serviceId: tensquare_gathering
    tensquare_qa:
      path: /qa/**
      serviceId: tensquare_qa
    tensquare_recruit:
      path: /recruit/**
      serviceId: tensquare_recruit
    tensquare_spit:
      path: /spit/**
      serviceId: tensquare_spit
    tensquare_user:
      path: /user/**
      serviceId: tensquare_user

启动类:

用这个来开启Zuul的网关效果

在这里插入图片描述
然后我们按照顺序,我们启动EurekaApplication,BaseApplication,ManagerApplication

这个时候,我们访问base模块(端口9001)的一个接口,用原始的路径去访问的话:

自然是可以正常连通的,这没问题吧

在这里插入图片描述

而网关的作用是什么呢,就是让我们访问Manager模块(端口号9012),但是能通过路由表,找到我们任意工程内的一个模块

在这里插入图片描述

而这个路径是如何选择的呢,以贴图为例,我们找到配置文件:

在这里插入图片描述

意思也就是说,当我们选中了Manager网关模块的9012端口,并且把url自动带上/base之后,就可以自动去映射到你serviceId指定的模块了,然后再跟上你这个匹配模块的控制层,就能自由的去发送http请求了。

而网关在映射的过程中,也是存在过滤的能力的,并且这个过滤器已经被封装好了,我们可以通过集成ZuulFilter来实现过滤,我下面来介绍一下过滤器中的四个方法:

在这里插入图片描述
但如果我们需要转发Authorization给该有的模块,做权限验证的话,就需要获得到Http请求的上下文,然后再传递给转发的模块。

于是我们可以写一个在前台专门来获取request上下文并且转发的WebFilter。

@Component
public class WebFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //得到 request上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        //得到request域
        HttpServletRequest request = currentContext.getRequest();
        //得到头信息
        String header = request.getHeader("Authorization");
        //判断是否真的有头信息
        System.out.println(header);
        if (header != null && !"".equals(header)) {
            //把头信息继续向下传
            currentContext.addZuulRequestHeader("Authorization", header);

        }
        return null;
    }
}

之后,我们获取到了头信息,也就间接的获取到了token给了后端,现在我们要做的是将token去解析出来,获取到用户的角色信息,权限信息等等。

在这里,我们所选的是无状态的jwt整合SpringSecurity去做的token加密。

JWTUtil的工具类,yml等等就不说了,主要说一些核心内容,SpringSecurity整合jwt的无状态认证授权也可以看这篇文章。

https://blog.csdn.net/qq_41936805/article/details/102780732

好,那我们既然已经将Authorization这个Header传下去了,那么接下来我们就需要通过他获取到的token去解析,然后进行一个统一的配置。

我们可以用getRole来获取到角色,然后进行统一的拦截,也就相当于是一个过滤器了,所以我们也就把相关代码继续写在刚才的过滤器里面,只不过不是写在前台过滤器WebFilter,而是写经由WebFilter传递token的后台过滤器ManagerFilter.

在这里,我们可以进行统一的配置

@Component
public class ManagerFilter extends ZuulFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public String filterType() {
        //return "pre"代表操作之前执行过滤,return "post"代表操作之后执行
        return "pre";
    }

    @Override
    public int filterOrder() {
        //0表示优先执行,当我们有很多过滤器的时候,可以用数字表示执行的级别,数字越小级别越高
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        //当前过滤器是否开启,true是开启,false是关闭
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //过滤器内执行的操作 return 任何object的值都表示放行
        //setSendZuulResponse(false)表示不再继续执行
        RequestContext requestContext = RequestContext.getCurrentContext();
        //request域
        HttpServletRequest request = requestContext.getRequest();

        if (request.getMethod().equals("OPTIONS")) {
            return null;
        }

        if (request.getRequestURI().indexOf("login") > 0) {
            return null;
        }


        //得到头信息
        String header = request.getHeader("Authorization");
        if (header != null && !"".equals(header)) {
            if (header.startsWith("Bearer ")) {
                String token = header.substring(7);
                try {
                    Claims claims = jwtUtil.parseJWT(token);
                    String roles = (String) claims.get("role");
                    if (roles.equals("admin")) {
                        //把头信息转发,放行
                        requestContext.addZuulRequestHeader("Authorization", header);
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    requestContext.setSendZuulResponse(false);//终止运行

                }
            }
        }
        requestContext.setSendZuulResponse(false);//终止运行
        requestContext.setResponseStatusCode(403);//权限不足
        requestContext.setResponseBody("权限不足");
        requestContext.getResponse().setContentType("text/html;charset=utf-8");
        return null;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值