AWS SDK for Java v2 SRA Identity 与 Auth 支持设计决策解读从决策日志看身份抽象 API 的落地实现【免费下载链接】aws-sdk-java-v2The official AWS SDK for Java - Version 2项目地址: https://gitcode.com/GitHub_Trending/aw/aws-sdk-java-v2导读本文以 AWS SDK for Java v2 仓库中的 DecisionLog.md 为核心深入解读 Smithy Reference ArchitectureSRA背景下 Identity 与 Auth 支持的 API 设计决策。该决策日志记录了 2023 年 3 月 31 日一次 API 面评审会议的完整结论围绕三个核心问题展开AwsCredentialsIdentity接口是否提供create()工厂方法、AwsCredentialsProviderChain如何兼容新的 Identity 类型、IdentityResolver如何声明其支持的IdentityProperty。读完本文你将掌握这些决策背后的 Java 语言约束如方法重载与类型擦除、SDK 源码中的最终实现形态以及如何在identity-spi模块之上编写自定义 Identity Provider。文章同时给出全部关键源码的仓库相对路径方便你对照阅读。一、背景SRA 与 identity-spi 模块Smithy Reference ArchitectureSRA是 AWS 跨语言 SDK 的统一参考架构其核心目标之一是抽象出与具体凭证实现解耦的“身份Identity”概念。在 AWS SDK for Java v2 中这一抽象落地为独立的identity-spi模块位于 core/identity-spi对应 pom.xml。该模块定义了整套身份抽象的核心接口Identity表示“谁在使用 SDK”即用于认证的调用方身份提供可选的expirationTime()与providerName()默认方法AwsCredentialsIdentityAWS 凭证access key / secret access key的抽象AwsSessionCredentialsIdentity带 session token 的临时凭证抽象IdentityProvider加载身份的统一 SPI负责解析凭证、令牌等认证身份IdentityProperty强类型的属性键作为ResolveIdentityRequest的输入ResolveIdentityRequest向 Provider 请求解析身份的载体可携带属性。决策日志正是围绕这套新抽象在做 API 面API surface area评审时产出的产物。二、决策一AwsCredentialsIdentity提供create()工厂方法2.1 决策内容评审会议的第一个封闭决策是新接口AwsCredentialsIdentity应提供create()方法。理由有二让客户无需依赖auth模块中的AwsBasicCredentials即可轻松创建该类型实例即使与AwsBasicCredentials存在少量代码重复也是可以接受的create()的实现可以使用匿名内部类而不必新建一个具名类。2.2 源码印证该决策在 AwsCredentialsIdentity.java 中得到完整落地。接口同时提供了builder()与create()两条创建路径static Builder builder() { return DefaultAwsCredentialsIdentity.builder(); } static AwsCredentialsIdentity create(String accessKeyId, String secretAccessKey) { return builder().accessKeyId(accessKeyId) .secretAccessKey(secretAccessKey) .build(); }从源码可见最终实现并非决策中讨论的“匿名内部类”而是采用具名的DefaultAwsCredentialsIdentity默认实现即 internal/DefaultAwsCredentialsIdentity。这属于实现细节在评审后的自然演进——决策保留了“用户无需依赖 auth 模块即可创建实例”的核心诉求而create()内部委托给builder()保持两条 API 路径行为一致。2.3 接口全貌AwsCredentialsIdentity是SdkPublicApi与ThreadSafe注解的公开接口提供以下核心契约accessKeyId()获取用于标识用户的访问密钥secretAccessKey()获取用于认证用户的秘密访问密钥accountId()默认返回Optional.empty()子类可覆盖以携带账号 IDBuilder接口支持accessKeyId、secretAccessKey、accountId以及默认的providerName()标识解析该身份的 Provider 名称默认 no-op。2.4 会话凭证的对称设计与之对称AwsSessionCredentialsIdentity源码继承AwsCredentialsIdentity并增加sessionToken()同样提供create(accessKeyId, secretAccessKey, sessionToken)工厂方法与独立的Builder。其 Javadoc 明确指出会话令牌通常由 STS 等令牌代理服务颁发用于证明用户已获得临时访问权限。对应单元测试位于 AwsCredentialsIdentityTest.java 与 AwsSessionCredentialsIdentityTest.java可对照验证创建与取值行为。三、决策二AwsCredentialsProviderChain如何支持新 Identity 类型3.1 决策内容与 Java 语言约束第二个封闭决策回答“AwsCredentialsProviderChain如何支持新的AwsCredentialsIdentity类型”会议给出三条方案重载Builder.addCredentialsProvider()使其接受新的类型重载 varargs 方法of()与Builder.credentialsProviders()。这一步的关键判断是零参数调用时不会产生歧义因为根据 Java 语言规范JLS 15.12.2.5编译器会选择更具体的方法——即AwsCredentialsProviderChain.of()会调用of(AwsCredentialsProvider...)接受Collection的重载不可行credentialsProviders(CollectionAwsCredentialsProvider)与credentialsProviders(CollectionIdentityProvider...)具有相同的类型擦除无法共存。因此采用不同方法名credentialsIdentityProviders()作为一次性特例而 varargs、add、of等方法刻意不加入Identity字样以免误导用户以为链上有两种不同的“属性”。3.2 源码印证该决策在 AwsCredentialsProviderChain.java 中完全落地。关键代码点如下链内部将凭证列表统一抽象为ListIdentityProvider? extends AwsCredentialsIdentity第 58 行并以lastUsedProvider缓存上次命中的 Provider静态工厂of(IdentityProvider? extends AwsCredentialsIdentity... awsCredentialsProviders)第 96 行接受新类型resolveCredentials()遍历链通过CompletableFutureUtils.joinLikeSync(provider.resolveIdentity())以同步方式解析异步身份Builder 提供三个入口第 172–199 行区域Builder credentialsIdentityProviders( Collection? extends IdentityProvider? extends AwsCredentialsIdentity credentialsProviders); default Builder credentialsProviders(IdentityProvider? extends AwsCredentialsIdentity... credentialsProviders) { ... } default Builder addCredentialsProvider(IdentityProvider? extends AwsCredentialsIdentity credentialsProvider) { ... }从源码可以确认credentialsProviders(...)与addCredentialsProvider(...)均以IdentityProvider? extends AwsCredentialsIdentity为参数类型从而同时接受旧式AwsCredentialsProvider其实现IdentityProviderAwsCredentialsIdentity与新式身份 Provider而集合形态的方法独占credentialsIdentityProviders名称正是为了避免类型擦除冲突——这与决策日志的判断完全一致。3.3 设计启示这一决策体现了两个值得借鉴的 Java API 设计原则重载与擦除的平衡varargs / 单元素方法可以安全重载因为编译器按“最具体方法”规则消解歧义但Collection泛型参数会退化为原始类型Collection必须用独立方法名绕开命名即语义仅在集合方法上使用Identity后缀是为了精准传达“这只是同一属性集合的另一种接收方式”避免 API 使用者误以为存在两类独立配置。四、决策三IdentityResolver如何声明支持的IdentityProperty4.1 决策内容第三个封闭决策规定每个IdentityResolver应为其支持的每个IdentityProperty声明public static常量并在 Javadoc 中说明resolveIdentity过程中如何使用该属性从而帮助调用方构造合适的ResolveIdentityRequest。会议还讨论了是否需要对某些属性提供更强的抽象例如 metrics collector / telemetry。结论是暂不引入除非出现令人信服的使用场景且这类属性若加入通用接口必须做到非 AWS 特定not AWS specific。4.2 源码印证IdentityProperty 的强类型设计IdentityProperty.java 是一个不可变、线程安全的强类型属性键public static T IdentityPropertyT create(Class? namespace, String name) { return new IdentityProperty(namespace.getName(), name); }它通过(namespace, name)二元组保证唯一性内部用ConcurrentHashMapNAME_HISTORY记录历史若出现同名重复创建会抛出IllegalArgumentException并在错误信息中提示“IdentityProperty应通过共享的 static 常量引用以防止错误或意外冲突”。这正是决策日志“声明public static常量”要求的强制机制重复定义同名属性在运行时就会被拦截。4.3 源码印证Provider 消费属性的完整链路ResolveIdentityRequest源码是属性传递的载体定义了一对读写方法T T property(IdentityPropertyT property); // 读取 T Builder putProperty(IdentityPropertyT key, T value); // 写入其 Javadoc 给出了典型动机身份可能随请求属性而变化例如 S3 按 bucket 使用不同凭证。IdentityProvider源码则展示了“public static 常量 消费属性”的推荐写法其 Javadoc 内嵌了可直接套用的代码片段public class RoleBasedCredentialsProvider implements IdentityProviderAwsCredentialsIdentity { public static final IdentityPropertyString ROLE_ARN IdentityProperty.create(RoleBasedCredentialsProvider.class, RoleArn); Override public CompletableFutureAwsCredentialsIdentity resolveIdentity(ResolveIdentityRequest request) { String roleArn request.property(ROLE_ARN); return assumeRoleAndGetCredentials(roleArn); } }4.4 关于“更强的抽象”与 IdentityPropertyTest决策中“暂不引入更强抽象”的态度在测试中也可见一斑。关于IdentityProperty唯一性、相等性equals/hashCode 基于 namespace 与 name与不可变性的验证可参考 IdentityPropertyTest.java 与 ResolveIdentityRequestTest.java。五、决策日志模板与开放问题5.1 日志模板的工程价值文档开头的 Log Entry Template 本身就是一个轻量级的 ADRArchitecture Decision Record模板包含四个字段Source决策来源会议 / 结对编程讨论 / 每日站会等与讨论主题Attendees与会人员Closed Decisions已封闭的决策每条按“问题 → 决策 → 理由”三段式记录Open Decisions遗留的开放问题标注状态Old / Reopened / New。本次 3/31/23 评审的与会者为 Anna-Karin、David、Debora、Dongie、Jay、John、Matt、Olivier、Zoe开放决策为None——三个核心问题全部封闭。5.2 从日志到实现的一致性将日志结论与仓库现状对照可确认三条决策均已在主干代码中生效决策日志条目仓库落地点AwsCredentialsIdentity提供create()AwsCredentialsIdentity.java 中create()与builder()Chain 重载 varargs / add集合用独立方法名AwsCredentialsProviderChain.java 中of(...)、credentialsProviders(...)、addCredentialsProvider(...)、credentialsIdentityProviders(...)IdentityResolver 以public static声明属性IdentityProvider.java 的ROLE_ARN示例与 IdentityProperty.java 的唯一性强制机制六、对 SDK 使用者的实践启示6.1 创建身份的新方式如果你的代码只依赖identity-spi模块现在可以直接用import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; AwsCredentialsIdentity identity AwsCredentialsIdentity.create(accessKey, secretKey); AwsSessionCredentialsIdentity session AwsSessionCredentialsIdentity.create(accessKey, secretKey, sessionToken);无需再为“仅创建实例”而引入auth模块的AwsBasicCredentials。6.2 自定义 Identity Provider 的落地步骤结合决策三与IdentityProvider的 Javadoc 示例实现一个自定义 Provider 只需三步实现IdentityProviderAwsCredentialsIdentity返回identityType()以public static final IdentityPropertyT声明所需属性并文档化resolveIdentity中对它的使用在resolveIdentity(ResolveIdentityRequest)中通过request.property(...)读取属性并解析身份返回CompletableFuture。注意IdentityProperty.create(namespace, name)的 namespace 应传属性定义所在的类且属性必须由共享的 static 常量引用否则运行时唯一性校验会直接抛异常——这是 SDK 用强制机制落实“可发现、可文档化”设计意图的体现。七、相关设计文档导航SRA Identity 与 Auth 决策日志docs/design/core/sra-identity-auth/DecisionLog.md核心身份抽象模块core/identity-spi模块定义见 pom.xml凭证链实现auth 模块core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java身份 SPI 测试core/identity-spi/src/test仓库整体设计文档索引docs/design/core/README.md结语一份不足五十行的决策日志背后是 Java 重载消歧、类型擦除、SPI 可扩展性等一整套工程权衡。通过将 DecisionLog.md 与 identity-spi 模块源码逐一对照可以看到 AWS SDK for Java v2 是如何把“决策”稳健地翻译为“实现”的AwsCredentialsIdentity的双路径创建、AwsCredentialsProviderChain的命名取舍、IdentityProperty的运行时唯一性保障共同构成了 SRA 身份抽象中既灵活又克制的 API 面。对于希望在自定义认证链路上扩展 SDK 的开发者这三条决策及其落地代码即是可直接复用的最佳范本。【免费下载链接】aws-sdk-java-v2The official AWS SDK for Java - Version 2项目地址: https://gitcode.com/GitHub_Trending/aw/aws-sdk-java-v2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考