欢迎光临
我们一直在努力

SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的?

在这里插入图片描述

最近在看 SeaTunnel Zeta Engine 的 REST API 认证逻辑时,遇到一个很典型的问题:

Zeta Engine 明明已经启动了,REST 服务也正常监听端口,但是访问 /overview、/running-jobs、/job-info 这些接口时,却返回了:

HTTP/1.1 401 Unauthorized

如果只是第一次看到这个错误,很容易以为是服务没有启动、端口写错了,或者接口路径不对。

但实际上,这类问题很多时候和 SeaTunnel Zeta Engine 的 Basic Auth 配置有关。

当 Zeta Engine 开启 Basic Auth 后,客户端再访问 REST API,就不能像之前一样直接请求接口,而是必须在请求头里带上正确的认证信息。

这篇文章就从这个 401 问题开始,简单看一下 SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的,以及客户端应该如何正确连接。


1. 先说现象:访问 Zeta REST API 返回 401

假设我们直接访问 Zeta Engine 的 REST API:

curl http://localhost:8080/overview

如果没有开启 Basic Auth,这个请求可以正常返回 Zeta Engine 的概要信息。

但是当配置里开启 Basic Auth 后,如果请求没有携带认证信息,就会返回:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="SeaTunnel Web UI"

这说明请求已经到达了 Zeta Engine,但在进入真正的 REST Servlet 之前,被认证过滤器拦截了。

也就是说:

Zeta Engine 正常运行
REST API 地址也没有问题
但是客户端没有带 Authorization 请求头
所以被 BasicAuthFilter 拦截并返回 401

Basic Auth 本身并不复杂,它本质上就是在 HTTP Header 中增加一段认证信息:

Authorization: Basic base64(username:password)

例如用户名是 admin,密码是 admin,客户端最终需要把:

admin:admin

做 Base64 编码,然后放到 Authorization 请求头里。


2. 看源码:BasicAuthFilter 如何拦截请求

SeaTunnel Zeta Engine 的 Basic Auth 核心逻辑在 BasicAuthFilter 中。

这个类实现了标准的 Servlet Filter:

public class BasicAuthFilter implements Filter {
private final HttpConfig httpConfig;

public BasicAuthFilter(HttpConfig httpConfig) {
this.httpConfig = httpConfig;
}
}

Filter 的特点是:请求进入真正的 Servlet 之前,会先经过过滤器。

所以 Basic Auth 的认证逻辑并不是写在某一个具体接口里,而是在统一的过滤器中完成的。

核心代码在 doFilter 方法里。

首先,它会判断是否开启 Basic Auth:

if (!httpConfig.isEnableBasicAuth()) {
chain.doFilter(request, response);
return;
}

这段代码很关键。

如果没有开启 Basic Auth,请求会直接放行:

chain.doFilter(request, response);

也就是说,enable-basic-auth 没有开启时,REST API 不需要认证。

如果开启了 Basic Auth,代码会继续往下走,开始读取 HTTP 请求头:

HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;

String authHeader = httpRequest.getHeader("Authorization");

然后判断请求头是否存在,并且是否以 Basic 开头:

if (authHeader != null && authHeader.startsWith("Basic ")) {
String base64Credentials = authHeader.substring("Basic ".length());
String credentials =
new String(Base64.decodeBase64(base64Credentials), StandardCharsets.UTF_8);

final String[] values = credentials.split(":", 2);
}

这里做了几件事:

  • 从请求头中取出 Authorization
  • 去掉前面的 Basic
  • 对后面的内容进行 Base64 解码
  • 将解码后的字符串按 : 拆分成用户名和密码
  • 比如请求头是:

    Authorization: Basic YWRtaW46YWRtaW4=

    解码后就是:

    admin:admin

    然后代码会和配置中的用户名、密码进行比较:

    if (username.equals(httpConfig.getBasicAuthUsername())
    && password.equals(httpConfig.getBasicAuthPassword())) {
    chain.doFilter(request, response);
    return;
    }

    如果用户名和密码都正确,请求继续放行。

    如果请求头不存在、格式不正确、用户名密码不匹配,就会返回 401:

    httpResponse.setHeader("WWW-Authenticate", "Basic realm=\\"SeaTunnel Web UI\\"");
    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

    所以 BasicAuthFilter 的整体流程可以理解成:

    请求进入 Zeta REST 服务

    判断是否开启 Basic Auth

    未开启:直接放行

    已开启:读取 Authorization 请求头

    解析 Basic Auth 用户名和密码

    和配置中的 username/password 比较

    匹配成功:放行
    匹配失败:返回 401 Unauthorized


    3. 看配置:enable-basic-auth、username、password 如何生效

    Basic Auth 相关的核心配置主要有三个:

    参数是否必填说明
    enable-basic-auth No 是否开启 Basic Auth,默认是 false
    basic-auth-username No Basic Auth 用户名,默认是 admin
    basic-auth-password No Basic Auth 密码,默认是 admin

    也就是说,默认情况下:

    enable-basic-auth = false
    basic-auth-username = admin
    basic-auth-password = admin

    这里要注意一点:

    虽然 basic-auth-username 和 basic-auth-password 默认都是 admin,但是如果 enable-basic-auth 没有开启,它们并不会生效。

    真正决定是否启用认证的是:

    enable-basic-auth

    如果它是 false,Zeta Engine 的 REST API 不会要求客户端携带 Basic Auth。

    如果它是 true,所有被 BasicAuthFilter 保护的请求都需要认证。

    一个示例配置大概是这样:

    seatunnel {
    engine {
    http {
    enable-http = true
    port = 8080

    enable-basic-auth = true
    basic-auth-username = "admin"
    basic-auth-password = "admin"
    }
    }
    }

    开启后,普通请求就会失败:

    curl http://localhost:8080/overview

    返回:

    401 Unauthorized

    正确的访问方式应该是:

    curl -u admin:admin http://localhost:8080/overview

    或者显式传递 Header:

    curl \\
    -H "Authorization: Basic YWRtaW46YWRtaW4=" \\
    http://localhost:8080/overview

    这里的 YWRtaW46YWRtaW4= 就是 admin:admin 的 Base64 编码。


    4. 看客户端:如何通过 Authorization Header 连接

    理解了服务端的认证逻辑后,客户端要做的事情就很明确了:

    只要 Zeta Engine 开启了 Basic Auth,客户端请求 REST API 时,就必须带上:

    Authorization: Basic base64(username:password)

    如果用 Java 代码访问,可以直接使用 Spring 的 HttpHeaders#setBasicAuth。

    例如:

    HttpHeaders headers = new HttpHeaders();
    headers.setBasicAuth("admin", "admin", StandardCharsets.UTF_8);

    HttpEntity<Void> entity = new HttpEntity<>(headers);

    ResponseEntity<Map> response = restTemplate.exchange(
    "http://localhost:8080/overview",
    HttpMethod.GET,
    entity,
    Map.class
    );

    这段代码会自动生成 Basic Auth 请求头,不需要我们手动做 Base64 编码。

    如果想封装得更通用一点,可以把认证逻辑独立成一个方法:

    private void applyBasicAuth(HttpHeaders headers, String username, String password) {
    if (username == null || username.trim().isEmpty()) {
    return;
    }

    if (password == null || password.trim().isEmpty()) {
    return;
    }

    headers.setBasicAuth(
    username.trim(),
    password,
    StandardCharsets.UTF_8
    );
    }

    然后每次请求 Zeta REST API 前,都统一调用:

    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

    applyBasicAuth(headers, username, password);

    这样无论是 GET 请求:

    restTemplate.exchange(
    "http://localhost:8080/running-jobs",
    HttpMethod.GET,
    new HttpEntity<Void>(null, headers),
    List.class
    );

    还是 POST 请求:

    restTemplate.exchange(
    "http://localhost:8080/submit-job",
    HttpMethod.POST,
    new HttpEntity<>(configText, headers),
    Map.class
    );

    都可以统一带上认证信息。

    这也是客户端连接开启 Basic Auth 的 Zeta Engine 时最核心的一点:

    不是 REST API 变了
    也不是接口路径变了
    只是请求头中必须多一个 Authorization


    5. 最后补充:SeaTunnel Web 如何把这一步可视化

    image.png 前面讲的是 SeaTunnel Zeta Engine 层面的 Basic Auth 逻辑。

    如果直接用代码连接,我们需要自己维护:

    Zeta Engine 地址
    端口
    是否开启 Basic Auth
    用户名
    密码

    然后在每次请求 REST API 时,把认证信息加到请求头里。

    但对于很多使用者来说,他们并不希望每次都手动写代码、拼 Header、测试接口。

    所以在 SeaTunnel Web 中,可以把这一步做成可视化配置。

    比如新增一个 Zeta Engine 客户端时,页面上可以提供这些配置项:

    Client Name
    Engine Type
    Client Address
    Client Port
    Enable Basic Auth
    Username
    Password

    当用户开启 Basic Auth,并填写用户名密码后,SeaTunnel Web 在请求 Zeta REST API 时,自动补充:

    Authorization: Basic xxx

    这样用户点击“测试连接”时,背后实际访问的还是 Zeta Engine 的 /overview 接口,只是 SeaTunnel Web 帮用户把认证请求头处理好了。

    保存客户端后,后续访问这些接口:

    /overview
    /running-jobs
    /job-info
    /finished-jobs
    /submit-job
    /submit-job/upload
    /stop-job
    /metrics

    也都可以基于保存的客户端配置,自动带上 Basic Auth。

    这样做的好处是:

    SeaTunnel Zeta Engine 仍然保持原有的 REST 认证机制
    SeaTunnel Web 只是把认证配置可视化
    用户不需要关心 Authorization Header 的细节


    小结

    SeaTunnel Zeta Engine 的 Basic Auth 逻辑并不复杂,但它很容易在第一次使用时造成 401 问题。

    核心可以总结成几句话:

  • enable-basic-auth 默认是 false,不开启时 REST API 不需要认证。
  • 开启 Basic Auth 后,Zeta Engine 会通过 BasicAuthFilter 拦截请求。
  • 客户端必须在请求头中携带 Authorization: Basic xxx。
  • xxx 是 username:password 的 Base64 编码。
  • basic-auth-username 和 basic-auth-password 默认都是 admin。
  • SeaTunnel Web 可以把这个过程可视化,让用户通过页面配置完成认证连接。
  • 所以,当我们遇到:

    401 Unauthorized

    不要第一时间怀疑 Zeta Engine 没启动,也不要只看端口和接口路径。

    更应该先确认:

    是否开启了 enable-basic-auth
    客户端是否带了 Authorization 请求头
    用户名和密码是否和配置一致

    理解了这一点,再看 SeaTunnel Zeta Engine 的 REST API 认证流程,就会清楚很多。

    写在最后

    SeaTunnel Web 是我正在持续完善的一个 SeaTunnel 可视化项目,希望把数据源管理、Zeta Engine 连接、任务配置、运行日志和指标查看这些常用能力,做得更直观、更容易上手。

    项目地址:

    https://github.com/weifuwan/seatunnel-web

    里面有体验地址、部署文档、社区交流群

    如果你也在学习 SeaTunnel,或者正在做数据同步、数据集成相关的事情,也欢迎一起交流。

    这里有一群上进的小伙伴,也有一群爱分享的大佬。大家可以一起讨论问题、分享实践、完善文档,也一起把 SeaTunnel 这件事讲得更清楚、做得更好用。

    赞(0)
    未经允许不得转载:171主机测评 » SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的?
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址