|
3 | 3 | import io.github.easy4j.hermes.api.model.*; |
4 | 4 | import io.github.easy4j.hermes.cli.HermesCli; |
5 | 5 | import io.github.easy4j.hermes.cli.HermesCliExecutor; |
| 6 | +import io.github.easy4j.hermes.security.ProfileBinding; |
| 7 | +import io.github.easy4j.hermes.security.ProfileCredentialResolver; |
| 8 | +import io.github.easy4j.hermes.security.ProfileIdentity; |
6 | 9 | import io.github.easy4j.hermes.api.HermesHttpClient; |
7 | 10 | import io.github.easy4j.hermes.api.HermesChatClient; |
8 | 11 | import io.github.easy4j.hermes.api.HermesSseClient; |
@@ -94,6 +97,7 @@ public class HermesClient implements AutoCloseable { |
94 | 97 | public HermesClient(HermesClientConfig config) { |
95 | 98 | this(Objects.requireNonNull(config, "config").getHttp(), config.getCli(), new ObjectMapper(), |
96 | 99 | HermesOkHttpClientFactory.create(config.getHttp()), true); |
| 100 | + this.config.setProfileCredentialResolver(config.getProfileCredentialResolver()); |
97 | 101 | } |
98 | 102 |
|
99 | 103 | /** |
@@ -125,6 +129,7 @@ public HermesClient(HermesClientConfig config, ObjectMapper objectMapper, OkHttp |
125 | 129 | objectMapper, |
126 | 130 | httpClient, |
127 | 131 | false); |
| 132 | + this.config.setProfileCredentialResolver(config.getProfileCredentialResolver()); |
128 | 133 | } |
129 | 134 |
|
130 | 135 | /** |
@@ -323,6 +328,8 @@ private static void copyHttpConfig(HermesHttpClientConfig src, HermesHttpClientC |
323 | 328 | target.setEndpointPolicy(src.getEndpointPolicy()); |
324 | 329 | target.setBaseUrl(src.getBaseUrl()); |
325 | 330 | target.setApiKey(src.getApiKey()); |
| 331 | + target.setCredentialProvider(src.getCredentialProvider()); |
| 332 | + target.setProfileIdentity(src.getProfileIdentity()); |
326 | 333 | target.setConnectTimeoutMillis(src.getConnectTimeoutMillis()); |
327 | 334 | target.setReadTimeoutMillis(src.getReadTimeoutMillis()); |
328 | 335 | target.setWriteTimeoutMillis(src.getWriteTimeoutMillis()); |
@@ -1066,16 +1073,47 @@ public HermesClient forProfile(String profileId) { |
1066 | 1073 | throw new IllegalStateException("Hermes HTTP client is disabled"); |
1067 | 1074 | } |
1068 | 1075 | String normalizedProfileId = normalizeProfileId(profileId); |
1069 | | - // 并发访问同一 profile 时只发布一个托管视图。 |
1070 | | - return profileClients.computeIfAbsent(normalizedProfileId, this::createProfileClient); |
| 1076 | + ProfileCredentialResolver resolver = config.getProfileCredentialResolver(); |
| 1077 | + if (resolver == null) { |
| 1078 | + throw new IllegalStateException("No credential is configured for Hermes profile " |
| 1079 | + + normalizedProfileId + "; root credentials are never inherited by named profiles"); |
| 1080 | + } |
| 1081 | + ProfileBinding binding = resolver.resolve(normalizedProfileId); |
| 1082 | + if (binding == null) { |
| 1083 | + throw new IllegalStateException("No credential is configured for Hermes profile " + normalizedProfileId); |
| 1084 | + } |
| 1085 | + if (!normalizedProfileId.equals(binding.getProfileId())) { |
| 1086 | + throw new IllegalStateException("Profile credential resolver returned a binding for " |
| 1087 | + + binding.getProfileId() + " instead of " + normalizedProfileId); |
| 1088 | + } |
| 1089 | + return forProfile(binding); |
| 1090 | + } |
| 1091 | + |
| 1092 | + public HermesClient forProfile(ProfileBinding binding) { |
| 1093 | + Objects.requireNonNull(binding, "binding"); |
| 1094 | + if (managedProfileView) { |
| 1095 | + throw new IllegalStateException("Cannot create a profile client from another profile client"); |
| 1096 | + } |
| 1097 | + if (closed.get()) { |
| 1098 | + throw new IllegalStateException("HermesClient is closed"); |
| 1099 | + } |
| 1100 | + if (!isHttpEnabled()) { |
| 1101 | + throw new IllegalStateException("Hermes HTTP client is disabled"); |
| 1102 | + } |
| 1103 | + String profileId = normalizeProfileId(binding.getProfileId()); |
| 1104 | + String cacheKey = config.getHttp().getBaseUrl() + "|" + profileId + "|" + binding.getCredentialIdentity(); |
| 1105 | + return profileClients.computeIfAbsent(cacheKey, ignored -> createProfileClient(binding, profileId)); |
1071 | 1106 | } |
1072 | 1107 |
|
1073 | | - private HermesClient createProfileClient(String profileId) { |
| 1108 | + private HermesClient createProfileClient(ProfileBinding binding, String profileId) { |
1074 | 1109 | HermesHttpClientConfig profileConfig = new HermesHttpClientConfig(); |
1075 | 1110 | copyHttpConfig(config.getHttp(), profileConfig); |
1076 | | - // profile 只改变 URL 前缀并禁用重复探测,传输和 JSON 配置继续复用根客户端。 |
1077 | 1111 | profileConfig.setBaseUrl(profileServerUrl(config.getHttp().getBaseUrl(), profileId)); |
1078 | 1112 | profileConfig.setStartupCheckEnabled(false); |
| 1113 | + profileConfig.setApiKey(null); |
| 1114 | + profileConfig.setProfileIdentity(new ProfileIdentity( |
| 1115 | + config.getHttp().getBaseUrl(), profileId, binding.getCredentialIdentity())); |
| 1116 | + profileConfig.setCredentialProvider(binding.getCredentialProvider()); |
1079 | 1117 | HermesCliConfig disabledCli = new HermesCliConfig(); |
1080 | 1118 | disabledCli.setEnabled(false); |
1081 | 1119 | return new HermesClient(profileConfig, disabledCli, objectMapper, sharedHttpClient, false, true); |
|
0 commit comments