Spring Cloud Gateway组件详情介绍

一.引言

springcloud五大组件是:1.注册中心组件(Eurke),负责注册微服务,让服务之间可以相互认识,找到;2.负载均衡组件(Ribbon),各个微服务进行分摊处理,保护性能;3.熔断器组件(Resilience4j)。处理各个微服务之间调用时出现的容错情况,保护系统,控制故障范围。4.网关服务组件(Spring Cloud Gateway),负责api网关,路由配置功能。5.配置中心(Spring Cloud Config),负责管理微服务的配置文件。下面用一张图来描述它们之间的关系。

 二.网关的作用及功能

在Spring Cloud中有多个微服务,每个服务都有自己的地址,导致地址太多,每次调用后端都太麻烦,要不停的更改后端地址。而网关就是解决这个问题的,我们把所有的微服务的地址都写在Spring Cloud Gateway的配置中。客户端调用时直接调用网关地址就行了,让网关去匹配调用的地址接口。

三.核心概念

1.路由(Route):网关最基本的模块。它由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。

2.断言(Predicate):路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。

3.过滤器(Filter):过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。

四.用户鉴权(JWT)

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的声明规范。定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。特别适合于分布式站点的单点登录(SSO)场景。说白了,就是用于系统安全登录的鉴别,防止信息泄露。传统的用户信息保存在session中,session保存在服务器中。服务器携带session进行系统登录。JWT用户信息保存在客户端中。好处在于更加安全,服务端开销减小。JWT登录方式如下图。

五.Spring Cloud Gateway实战

目标:使用网关调用cloud-auth-user6500下的登录(user/login)接口,实现JWT用户鉴权。

1.创建项目,微服务可以多创建几个,首先都要注册到注册中心上。

 2.cloud-gateway-gateway9527项目的配置文件application。配置服务的路由routes:

分别配置对应的id,uri,predicates。把项目中的服务都配置到routes下

路由id:没有固定名,要唯一。

uri:匹配后提供服务的路由地址 lb后跟提供服务的微服务的名。

predicates:路径相匹配的进行路由,**代表该路径下的全部接口。

spring:
  cloud:
    gateway:
      routes:
        - id: cloud-auth-user
          uri: lb://CLOUD-AUTH-USER
          predicates:
            - Path=/user/*
        - id: payment_provider
            # 匹配后提供服务的路由地址 lb后跟提供服务的微服务的名
          uri: lb://cloud-payment-provide
            # 断言
          predicates:
              # 路径相匹配的进行路由
            - Path=/payment/**

3.编写全局过滤器,实现登录过滤,携带token的地址可以访问,没用token的不可以访问。实现安全登录。

package com.qs.config;

import com.alibaba.fastjson.JSONObject;
import com.qs.common.Response;
import com.qs.utils.JWTUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 用户全局过滤器
 */
@Data
@Slf4j
@Component
@ConfigurationProperties("org.my.jwt")
public class UserAuthGlobalFilter implements GlobalFilter, Ordered {

    // 跳过路由数组
    private String[] skipAuthUrls;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //获取请求url地址
        String url = exchange.getRequest().getURI().getPath();

        //跳过不需要验证的路径
        if (null != skipAuthUrls && isSkipUrl(url)) {
            return chain.filter(exchange);
        }

        //从请求中获取token令牌
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        //判断token是否存在
        if (StringUtils.isEmpty(token)) {
            //设置响应
            ServerHttpResponse response = exchange.getResponse();
            //设置响应状态
            response.setStatusCode(HttpStatus.OK);
            //设置响应头
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            //创建响应对象
            Response res = new Response(200, "确少token参数");
            //对象转字符串
            byte[] responseByte = JSONObject.toJSONString(res).toString().getBytes(StandardCharsets.UTF_8);
            //数据流返回数据
            DataBuffer buffer = response.bufferFactory().wrap(responseByte);
            return response.writeWith(Flux.just(buffer));
        }
        Boolean verify = JWTUtil.verify(token);
        if (!verify) {
            //设置响应
            ServerHttpResponse response = exchange.getResponse();
            //设置响应状态
            response.setStatusCode(HttpStatus.OK);
            //设置响应头
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            //创建响应对象
            Response res = new Response(200, "token失效");
            //对象转字符串
            byte[] responseByte = JSONObject.toJSONString(res).toString().getBytes(StandardCharsets.UTF_8);
            //数据流返回数据
            DataBuffer buffer = response.bufferFactory().wrap(responseByte);
            return response.writeWith(Flux.just(buffer));
        }

         //如果各种判断都通过,执行chain上的其他业务逻辑
        return chain.filter(exchange);
    }

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

    /**
     * 判断当前访问的url是否开头URI是在配置的忽略url列表中
     *
     * @param url
     * @return
     */
    public boolean isSkipUrl(String url) {
        for (String skipAuthUrl : skipAuthUrls) {
            if (url.startsWith(skipAuthUrl)) {
                return true;
            }
        }
        return false;
    }
}

4.登录接口跳过token认证。在所有的服务中,只有登录是不需要token认证的,登录时生产token,如果登录需要token认证,那么程序就陷入死循环,会一直登录不上。所以要设置跳过登录token认证,在application.yml文件中添加org配置。

org:
  my:
    jwt:
      #跳过认证的路由
      skipAuthUrls:
        - /user/login

5.启动项目,用户登录,用户登录成功回生成token。在之后调用其他接口时都要在头部中携带该token值才能调用成功。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值