☰
lakeFS Java SDK 的 CredentialsWithSecret 模型:凭证字段语义、认证流程与安全实践
2026/10/12 3:15:54 网站建设 项目流程
  • 数据工程
  • 数据湖
  • 大数据
  • 对象存储
  • 后端

【免费下载链接】lakeFS

lakeFS - Data version control for your data lake | Git for data

项目地址:https://gitcode.com/gh_mirrors/la/lakeFS
点击查看免费下载

本文以 lakeFS 仓库中由 OpenAPI Generator 自动生成的 CredentialsWithSecret.md 模型文档为核心,结合服务端 Go 实现与 Java SDK 源码,系统讲解 lakeFS 访问凭证(Access Key / Secret Key)的完整生命周期:该模型如何在创建凭证时返回明文 Secret、各字段的语义与 JSON 映射、Java 客户端调用方式,以及服务端如何生成、加密与存储这些凭证。读完本文,你将掌握 lakeFS 认证体系中"创建凭证 → 获取一次性明文 Secret → 客户端鉴权使用"这条完整链路,并能正确、安全地在 Java 项目中集成 lakeFS 凭证管理。

一、CredentialsWithSecret 是什么

CredentialsWithSecret是 lakeFS HTTP API 中定义的一个响应模型,用于表示创建凭证接口返回的完整凭证信息。与普通的Credentials模型不同,它额外携带了secret_access_key(密钥),因此命名为 "WithSecret"——即"带密钥的凭证"。

在 lakeFS 中,凭证由一对密钥组成:

  • Access Key ID(访问密钥 ID):对外公开的标识符,用于标识调用者身份;
  • Secret Access Key(密钥):与 Access Key ID 配套的机密字符串,用于签名请求、验证身份,必须严格保密。

CredentialsWithSecret就是这一对密钥加上创建时间戳的组合。它典型出现在两个场景的响应中:

  1. 为用户创建新凭证:POST /auth/users/{userId}/credentials,对应 Java SDK 的AuthApi.createCredentials;
  2. 初始化 lakeFS 安装(Setup):POST /setup_lakefs创建初始管理员用户时返回。

二、字段语义详解

原文档 CredentialsWithSecret.md 给出了该模型的完整属性表,本节在此基础上逐字段展开,并结合 api/swagger.yml 中的 OpenAPI 定义补充类型、必填约束与语义。

属性(Java 侧)JSON 字段类型说明必填
accessKeyIdaccess_key_idString访问密钥 ID,凭证的公开标识符是
secretAccessKeysecret_access_keyString密钥(Secret),仅在此响应中明文返回一次是
creationDatecreation_dateLong(int64)凭证创建时间,Unix Epoch 秒数(Unix Epoch in seconds)是

2.1 accessKeyId(访问密钥 ID)

用于标识凭证持有者的公开字符串。服务端生成规则位于 pkg/auth/keys/keys.go:

func GenAccessKeyID() string { const accessKeyLength = 14 key := KeyGenerator(accessKeyLength) return fmt.Sprintf("%s%s%s", "AKIAJ", key, "Q") }

生成的 Access Key ID 采用类似 AWS 的AKIAJ前缀风格,长度为 20 字符,中间 14 个字符取自AKIA字母表(ABCDEFGHIJKLMNOPQRSTUVWXYZ234567),整体形态形如AKIAJXXXXXXXXXXXXQ。从源码注释可知,这一字母表刻意排除了0和1等易混淆字符。

2.2 secretAccessKey(密钥)

与 Access Key ID 配对的机密字符串。生成规则同样位于 pkg/auth/keys/keys.go:

func GenSecretAccessKey() string { const secretKeyLength = 30 return Base64StringGenerator(secretKeyLength) }

即对 30 字节的密码学安全随机数(crypto/rand)做 Base64 编码,最终得到约 40 字符的随机密钥字符串。Secret 仅在创建凭证的响应中出现一次,之后服务端只保存其加密形式,无法再以明文查询——这是理解CredentialsWithSecret存在意义的关键(详见下文"安全注意事项")。

2.3 creationDate(创建时间)

凭证的签发时间,类型为Long,单位为秒的 Unix 时间戳。服务端在写入凭证时以time.Now()记录签发时间,见 pkg/auth/basic_service.go;响应中通过credentials.IssuedDate.Unix()转换为秒级时间戳输出,见 pkg/api/controller.go。

2.4 必填约束

OpenAPI 定义(api/swagger.yml)将access_key_id、secret_access_key、creation_date三个字段全部标记为required。这意味着:

  • 服务端在序列化响应时,三个字段一定存在;
  • 客户端反序列化时,如果响应缺少任一字段,将抛出异常(详见 CredentialsWithSecret.java 中的validateJsonElement校验逻辑)。

三、Java SDK 中的模型实现与 JSON 映射

3.1 类结构与序列化注解

Java SDK 中的对应类位于 clients/java/src/main/java/io/lakefs/clients/sdk/model/CredentialsWithSecret.java,由 OpenAPI Generator 基于api/swagger.yml自动生成,使用 Gson 完成序列化。类的开头即声明了三个字段与 JSON 键名的映射:

public static final String SERIALIZED_NAME_ACCESS_KEY_ID = "access_key_id"; @SerializedName(SERIALIZED_NAME_ACCESS_KEY_ID) private String accessKeyId; public static final String SERIALIZED_NAME_SECRET_ACCESS_KEY = "secret_access_key"; @SerializedName(SERIALIZED_NAME_SECRET_ACCESS_KEY) private String secretAccessKey; public static final String SERIALIZED_NAME_CREATION_DATE = "creation_date"; @SerializedName(SERIALIZED_NAME_CREATION_DATE) private Long creationDate;

注意 Java 侧采用驼峰命名(accessKeyId),而 JSON 侧采用下划线命名(access_key_id),二者通过@SerializedName建立映射,这是 OpenAPI 生成客户端中的常见约定。

3.2 方法能力

该类提供了一组完整的能力,便于开发与调试:

  • 链式构造器(setter 返回自身):accessKeyId(String)、secretAccessKey(String)、creationDate(Long),支持流式构建;
  • Getter:getAccessKeyId()、getSecretAccessKey()、getCreationDate(),三个字段均标注@Nonnull,与 OpenAPI 的 required 约束一致;
  • 附加属性支持:putAdditionalProperty(String, Object)与getAdditionalProperties()用于容纳服务端未来新增、当前 SDK 版本尚未声明的 JSON 字段,保证前后端兼容(CredentialsWithSecret.java);
  • JSON 工具方法:静态方法fromJson(String)可从 JSON 字符串反序列化,实例方法toJson()可序列化输出(CredentialsWithSecret.java)。

一个典型的手动反序列化示例:

import io.lakefs.clients.sdk.model.CredentialsWithSecret; String json = "{\"access_key_id\":\"AKIAJXXXXXXXXXXXXQ\",\"secret_access_key\":\"...\",\"creation_date\":1700000000}"; CredentialsWithSecret creds = CredentialsWithSecret.fromJson(json); System.out.println(creds.getAccessKeyId()); System.out.println(creds.getSecretAccessKey()); System.out.println(creds.getCreationDate());

四、在哪些 API 响应中出现

4.1 为用户创建凭证(AuthApi.createCredentials)

CredentialsWithSecret最核心的使用场景是创建凭证接口。在 AuthApi.md 中可以看到该接口的完整契约:

POST /auth/users/{userId}/credentials

请求无需请求体,路径参数为userId;成功时返回 HTTP201,响应体即为CredentialsWithSecret。Java SDK 对应方法位于 clients/java/src/main/java/io/lakefs/clients/sdk/AuthApi.java,其调用签名与使用方式:

CredentialsWithSecret result = apiInstance.createCredentials(userId) .execute();

服务端实现位于 pkg/api/controller.go。该处理器首先执行权限校验——调用者必须拥有对目标用户 ARN 的CreateCredentialsAction权限,随后调用Auth.CreateCredentials生成凭证,最后组装并返回CredentialsWithSecret:

response := apigen.CredentialsWithSecret{ AccessKeyId: credentials.AccessKeyID, SecretAccessKey: credentials.SecretAccessKey, CreationDate: credentials.IssuedDate.Unix(), } writeResponse(w, r, http.StatusCreated, response)

4.2 初始化安装(Setup)

CredentialsWithSecret还出现在 lakeFS 首次初始化时创建初始管理员用户的响应中。调用POST /setup_lakefs且未显式提供密钥时,服务端会生成随机凭证并返回,实现见 pkg/api/controller.go:

response := apigen.CredentialsWithSecret{ AccessKeyId: cred.AccessKeyID, SecretAccessKey: cred.SecretAccessKey, CreationDate: cred.IssuedDate.Unix(), } writeResponse(w, r, http.StatusOK, response)

若在 Setup 请求体中携带了自定义密钥(body.Key),则使用CreateInitialAdminUserWithKeys以指定密钥创建管理员(pkg/auth/setup/setup.go)。

五、完整 Java 调用示例

以下示例完整展示了如何在 Java 项目中配置认证并调用createCredentials,代码取自 AuthApi.md 并补充了关键注释:

import io.lakefs.clients.sdk.ApiClient; import io.lakefs.clients.sdk.ApiException; import io.lakefs.clients.sdk.Configuration; import io.lakefs.clients.sdk.auth.*; import io.lakefs.clients.sdk.model.CredentialsWithSecret; import io.lakefs.clients.sdk.AuthApi; public class CreateCredentialsExample { public static void main(String[] args) { ApiClient defaultClient = Configuration.getDefaultApiClient(); defaultClient.setBasePath("http://lakefs.example.com/api/v1"); // 方式一:HTTP Basic 认证(用户名 + 密码) HttpBasicAuth basic_auth = (HttpBasicAuth) defaultClient.getAuthentication("basic_auth"); basic_auth.setUsername("YOUR ADMIN USERNAME"); basic_auth.setPassword("YOUR ADMIN PASSWORD"); // 方式二:JWT Bearer Token HttpBearerAuth jwt_token = (HttpBearerAuth) defaultClient.getAuthentication("jwt_token"); jwt_token.setBearerToken("BEARER TOKEN"); AuthApi apiInstance = new AuthApi(defaultClient); String userId = "user_example"; // 为目标用户创建凭证 try { CredentialsWithSecret result = apiInstance.createCredentials(userId) .execute(); // 拿到一次性明文密钥 System.out.println("Access Key ID: " + result.getAccessKeyId()); System.out.println("Secret Access Key: " + result.getSecretAccessKey()); System.out.println("Creation Date (epoch seconds): " + result.getCreationDate()); } catch (ApiException e) { System.err.println("Exception when calling AuthApi#createCredentials"); System.err.println("Status code: " + e.getCode()); System.err.println("Reason: " + e.getResponseBody()); System.err.println("Response headers: " + e.getResponseHeaders()); e.printStackTrace(); } } }

该接口的认证方式支持basic_auth、cookie_auth、jwt_token三种(见 AuthApi.java),响应头要求Accept: application/json。可能的错误状态码包括400(Bad Request)、401(Unauthorized)、404(用户不存在)、429(请求过于频繁)等。

六、服务端实现原理:从生成到加密存储

要深入理解CredentialsWithSecret,需要看清服务端凭证的完整处理流程。核心逻辑位于 pkg/auth/basic_service.go:

  1. 生成密钥对:GenAccessKeyID()生成 Access Key ID,GenSecretAccessKey()生成明文 Secret;
  2. 校验用户存在:GetUser确认目标用户存在,不存在则返回错误;
  3. 配额校验:AddCredentials会检查该用户已有凭证数量,超过MaxCredentialsPerUser上限时拒绝创建(pkg/auth/basic_service.go);
  4. 加密存储:调用model.EncryptSecret使用SecretStore对明文 Secret 加密(pkg/auth/model/model.go),数据库中仅保存加密后的字节SecretAccessKeyEncryptedBytes(见 pkg/auth/model/model.go 中BaseCredential的结构:SecretAccessKey字段标注json:"-",明文不参与任何持久化与 JSON 输出);
  5. 返回明文一次:CreateCredentials处理器将明文SecretAccessKey组装进CredentialsWithSecret响应,这是明文 Secret 唯一一次出现在 API 输出中。

服务端对应的 Go 结构体定义在 pkg/api/apigen/lakefs.gen.go,与 Java 模型一一对应:

// CredentialsWithSecret defines model for CredentialsWithSecret. type CredentialsWithSecret struct { AccessKeyId string `json:"access_key_id"` // Unix Epoch in seconds CreationDate int64 `json:"creation_date"` SecretAccessKey string `json:"secret_access_key"` }

七、安全注意事项

由于CredentialsWithSecret携带明文密钥,使用时有几条必须遵守的安全准则:

  • 一次性获取:Secret 只在创建凭证的响应中明文返回,之后任何查询接口(如GetCredentials、ListUserCredentials)返回的都是不含 Secret 的Credentials模型。如果丢失了 Secret,只能删除该凭证并重新创建,无法找回。
  • 妥善保管:拿到CredentialsWithSecret后应立即持久化到安全的密钥管理设施(如环境变量、密钥管理系统),避免写入日志、代码仓库或前端。
  • 服务端只存密文:服务端以加密形式(SecretAccessKeyEncryptedBytes)落库,密钥解密依赖配置的SecretStore,降低了数据库泄露导致密钥暴露的风险。
  • 最小权限:创建凭证本身是敏感操作,服务端要求调用方持有CreateCredentialsAction权限(pkg/api/controller.go),生产环境应将此类操作限制在管理员账号。

八、与相关模型的区分

在 clients/java/docs 目录下,还有两个与凭证相关的模型,容易与CredentialsWithSecret混淆:

模型方向关键字段典型场景
CredentialsWithSecret响应(出参)access_key_id、secret_access_key、creation_date创建凭证、初始化管理员时的返回
Credentials响应(出参)access_key_id、creation_date列出 / 查询凭证(不含 Secret),见 Credentials.md
AccessKeyCredentials请求(入参)access_key_id、secret_access_keySetup 时指定初始管理员的自定义密钥,见 AccessKeyCredentials.md

区分要点:带 Secret 的模型只作为创建成功后的响应出现,且只出现一次;日常查询用Credentials;需要自定义密钥初始化时用AccessKeyCredentials作为输入。

九、小结

CredentialsWithSecret是 lakeFS 认证体系中一个短小但关键的模型:它定义了凭证创建场景下"Access Key ID + 明文 Secret + 创建时间"的响应契约。通过本文可以掌握:

  • 三个字段的类型、JSON 键名与必填约束(api/swagger.yml);
  • Java SDK 中对应的类、序列化映射与工具方法(CredentialsWithSecret.java);
  • 它在createCredentials与setup_lakefs两个接口中的使用方式;
  • 服务端生成随机密钥、加密存储、一次性返回明文的完整链路(basic_service.go、keys.go)。

理解这个模型,是安全使用 lakeFS Java SDK 管理用户凭证、构建自动化访问控制流程的基础。

  • 数据工程
  • 数据湖
  • 大数据
  • 对象存储
  • 后端

【免费下载链接】lakeFS

lakeFS - Data version control for your data lake | Git for data

项目地址:https://gitcode.com/gh_mirrors/la/lakeFS
点击查看免费下载

相关推荐

上一篇:如何快速掌握Node.js最佳实践:2024终极指南
下一篇:10分钟把PC游戏串流到客厅电视:Sunshine家庭串流搭建指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询