前言

以前我们使用的是zuul 然后实现了一些filter 所以,功能很简单,而且 性能也不太高,借着这次的机会,我负责架构的中间件,重新选型并使用一些主流的组件。

一 API gateway 主要功能

一般情况下,公司需要实现的网关功能有如下这些:

1.1 动态路由配置

1.2 灰度发布

1.2.1 接口版本控制

1.2.2 小程序、app 审核灰度

1.2.3 app升级,指定新版本

1.2.4 app不升级,指定新版本

1.3 限流

安全限流

1.3.1 sentinel

1.3.2 网关限流

1.4 黑白名单

  1. 黑名单禁止
  2. 白名单放行
  3. 白名单需要授权的走授权

    1.5 鉴权

    统一授权认证
    接口参数签名

    1.5.1 接口签名

    1.5.2 oauth2.0

    1.6 监控

    1.6.1 SkyWalking Trace 监控

    1.7 test

    聚合swagger

二 kong

2.1 安装部署

2.1.1 安装部署架构图

image.png

2.1.2 docker 安装

2.2 汉化

利用第三方个人实现的语言包,进行替换。

  1. docker stop kong_konga_1 #停止正在运行的容器
  2. docker cp kong_konga_1:/app/assets ./ #将容器的文件复制到本地
  3. docker pull jsonljd/konga-lang-plugin:latest #拉取语言插件镜像
  4. docker run -d --name konga-lang-plugin -v /Users/hezhaoming/Documents/docker/kong/assets:/app/assets jsonljd/konga-lang-plugin
  5. docker cp ./assets kong_konga_1:/app/ #覆盖成功后即可
  6. docker start kong_konga_1 #重启容器

2.3 konga 基本使用

2.3.1 upstream&target

首先需要新建上游,也就是我们反向代理的地址(我们的目标地址)。

  1. step1 创建上游

image.png

  1. step 创建管理target

image.png

  1. step 创建管理target

image.png

2.3.2 server

image.png

image.png

2.3.3 route

新增路由
image.png
image.png

2.3.4 执行过程原理

image.png

2.4 高级使用

2.4.1 网关监控

普罗米修斯
链路监控

2.4.2 日志监控

http tcp

2.4.3 限流

2.4.4 熔断重试

限制速率
限制包大小

2.4.5 鉴权

basic auth oauth 2.0 jwt

2.4.6 接口参数签名

接口安全三要素:合法身份、参数防篡改、防重放攻击(请求唯一)。展开来说分三步:

  1. 合法身份:
    1. 我们为开发者分配 AccessKey & Secretkey,即给第三方app调用方,分配一个合法的身份。
  2. 参数防篡改:
    1. 我们拼接字符串:str=MD5取摘要(stringA(key1=value1&key2=value2…)+Secretkey+timestap)
    2. sha(str,secret)加密
  3. 防重放攻击:
    1. timestamp+nonce:我们为没一个请求生成唯一key,即防止重复的请求,此外,根据时间戳,定期清除无用的nonce(我们可以利用redis的过期策略实现)。

上面说的签名验证方式,市面有很多实现,也可以自己手撸一个也无妨(我之前公司都是手撸的一套java+react),这里主要讨论的是kong的HAMC签名认证组件。

2.4.6.1 合法身份

前面说了,我们首先要为调用者APP 分配 accessKey ,Secretkey。
setp1. 新建api消费者
image.png
api创建方式:

curl -i -X POST http://localhost:8001/consumers/ \
 -d "username=alice"

setp2. 为第三方应用app分配 key、secre
image.png
api创建方式:

curl -i -X POST http://localhost:8001/consumers/alice/hmac-auth \
-d "username=alice123" \
-d "secret=secret"

2.4.6.2 为服务新建HMAC认证

注意:新增的签名认证填写任何参数image.png
api创建方式:

curl -i -X POST http://localhost:8001/services/jk-member-svc2/plugins \
      -d "name=hmac-auth" \

2.4.6.3 签名算法

这里涉及到两个算法,md5获取摘要,然后sha1加密,这里有个面试题:为啥不用原生的字符串加密,两个原因1. MD5摘要算法,长度固定,2. 不是明文显示保证安全性。

  1. MD5算法 ```java package cn.sephora;

import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;

/**

  • @author hezhaoming
  • @date 2020/11/23 */ public class Md5Util { public static String md5(String param) {
     if (StringUtils.isBlank(param)) {
         throw new IllegalArgumentException("param can not be null");
     }
     try {
         byte[] bytes = param.getBytes("utf-8");
         final MessageDigest md = MessageDigest.getInstance("MD5");
         md.reset();
         md.update(bytes);
         final Base64 base64 = new Base64();
         final byte[] enbytes = base64.encode(md.digest());
         return new String(enbytes);
     } catch (final NoSuchAlgorithmException e) {
         throw new IllegalArgumentException("unknown algorithm MD5");
     } catch (UnsupportedEncodingException e) {
         throw new RuntimeException(e);
     }
    
    } } ```
  1. HmacSha1Util算法 ```java package cn.sephora;

import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Formatter;

/**

  • @author hezhaoming
  • @date 2020/11/23 */ public class HmacSha1Util { private static final String HMAC_SHA1_ALGORITHM = “HmacSHA1”;

    private static String toHexString(byte[] bytes) {

     Formatter formatter = new Formatter();
     for (byte b : bytes) {
         formatter.format("%02x", b);
     }
     return formatter.toString();
    

    }

    public static String signature(String data, String key) throws NoSuchAlgorithmException, InvalidKeyException {

     SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
     Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
     mac.init(signingKey);
     return toHexString(mac.doFinal(data.getBytes()));
    

    }

    public static byte[] signatureReturnBytes(String data, String key) throws NoSuchAlgorithmException, InvalidKeyException {

     SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
     Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
     mac.init(signingKey);
     return mac.doFinal(data.getBytes());
    

    }

}


3. HmacTest
```java
package cn.sephora;

import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * @author hezhaoming
 * @date 2020/11/23
 */
@Slf4j
public class HmacTest {
    public static void main(String[] args) {
        test1();
    }

    static void test1() {
        String queryParam = "name=122&password=123";
        String contentMD5 = Md5Util.md5(queryParam);
        log.info("content-md5: {}", contentMD5);

        Date d = new Date();
        DateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String headerDate = format.format(d);
        log.info("x-date: {}", headerDate);

        StringBuilder stb = new StringBuilder();
        String content = stb.append("x-date: ").append(headerDate).append("\n").append("content-md5: ").append(contentMD5).toString();
        log.info("签名前内容: " + content);
        String secret = "secret";  //用户yanyuylou的密钥
        try {
            String signature2 = new String(Base64.getEncoder().encode(HmacSha1Util.signatureReturnBytes(content, secret)), "US-ASCII");
            log.info("显示指定编码[推荐]: {}", signature2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

2.4.6.4 测试demo

header 三个值
Content-md5       tkygbxlPERf+/tZghlMlXw==
X-Date           Mon, 23 Nov 2020 06:44:19 GMT
Authorization     Authorization: hmac username="alice123", algorithm="hmac-sha1", headers="x-date content-md5", signature="dojzuTSR3W/nhNJ+A9SY9+pJKTo="

image.png
api 测试方式

curl -i -X GET http://localhost/api2/user/getById/1 \
      -H "Content-md5: Qnwej0d5uZ9zgi34yYcoaw==" \
      -H "x-date: Mon, 23 Nov 2020 03:45:05 GMT" \
      -H 'Authorization: hmac username="alice123", algorithm="hmac-sha1", headers="x-date content-md5", signature="+Ro8wRWnVYdfvkZ8l4FFFPauBwE="'

2.4.7 黑白名单

Ip Restriction

2.4.8 灰度发布

社保版没有集成该插件

2.4.9 请求协议转化

request
response

三 spring gateway

3.1 nacas+gateway 实现动态路由

3.2 gateway实现 灰度发布

3.3 gateway 授权认证

3.4 哨兵限流熔断控制