Skip to content

Commit c7f623a

Browse files
CodeCasterXclaude
andauthored
[fit] Add comprehensive HTTP client authentication support with @requestauth annotation (#330)
* fix: Resolve parameter-applier mismatch in HTTP client authentication Fixes critical architecture issue where static auth appliers and parameter appliers were mixed in the same list, causing NullPointerException and parameter count mismatch errors. **Root Cause Analysis:** 1. NullPointerException: args=null for no-parameter methods 2. Count mismatch: staticAppliers + paramAppliers != args.length 3. Architecture flaw: mixed responsibilities in single applier list **Solution - Separated Applier Architecture:** - HttpInfo: Added staticAppliers and paramAppliers fields - HttpInvocationHandler: Separated execution (static first, then param) - AnnotationParser: Separated applier construction logic - Added null-safety for args parameter **Test Results:** ✅ No-parameter methods: testBearerStatic() now works ✅ Parameter methods: testBearerDynamic(token) now works ✅ All auth types: Bearer, Basic, API Key all functional ✅ Backward compatibility: existing appliers field maintained Closes #328 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * test: Add comprehensive unit tests for HttpInvocationHandler Add comprehensive unit tests for HttpInvocationHandler to cover the core issues discovered and fixed in the HTTP client authentication system: - Test null args handling to prevent NullPointerException - Test parameter count mismatch detection - Test static and parameter applier separation logic - Test HTTP info missing exception handling - Test multi-parameter method invocation Additionally improve code style consistency by: - Add this. prefix to all member variable accesses - Add proper resource management for MockitoAnnotations.openMocks() - Add explanatory comments for uncommon Mockito patterns These tests fill critical coverage gaps in the HttpInvocationHandler which previously had no direct unit tests, ensuring the parameter processing bugs discovered cannot reoccur. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * refactor: Remove redundant appliers field from HttpInfo Clean up the temporary backward-compatibility code by removing the unused appliers field, which was replaced by staticAppliers and paramAppliers. **Changes:** - HttpInfo: Remove appliers field and its getter/setter methods - AnnotationParser.parseMethod(): Directly set paramAppliers without temp variable - AnnotationParser.parseInterface(): Remove backward-compatibility merge logic - HttpInvocationHandlerTest: Remove appliers initialization from test setup **Benefits:** - Clearer separation of concerns between static and parameter appliers - Reduced code redundancy and maintenance burden - Improved code readability with more explicit variable names **Testing:** ✅ All 7 HttpInvocationHandler tests pass ✅ No functional changes, purely structural cleanup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * refactor: Refactor @requestauth to reuse AuthorizationDestinationSetter mechanism Unify the authentication architecture by making the @requestauth annotation system reuse the existing AuthorizationDestinationSetter and Authorization mechanisms, ensuring consistency with the FEL Tool system. **Architecture Improvements:** - Remove AuthDestinationSetter (duplicate implementation) - Modify StaticAuthApplier to directly create Authorization objects - Modify RequestAuthResolver to use AuthorizationDestinationSetter - Both annotation-based and JSON-based systems now use the same mechanism **Changes:** - StaticAuthApplier: Create Authorization objects directly via factory methods - RequestAuthResolver: Return AuthorizationDestinationSetter with appropriate keys - Remove AuthDestinationSetter and its test file - Update RequestAuthResolverTest to use AuthorizationDestinationSetter **Benefits:** - Eliminates code duplication in authentication logic - Ensures architectural consistency across different configuration methods - Simplifies maintenance with a single source of truth - Better follows the DestinationSetter design pattern **Testing:** ✅ All 225 tests pass ✅ RequestAuthResolverTest: 3/3 tests pass ✅ HttpInvocationHandlerTest: 7/7 tests pass ✅ No functional changes, purely architectural refactoring 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix: Add AuthProvider support to StaticAuthApplier Fix runtime error when using @requestauth with AuthProvider in class/method level static authentication scenarios. **Problem:** - StaticAuthApplier threw UnsupportedOperationException when encountering AuthProvider - Example 07 failed to start with "AuthProvider is not supported" error - Provider-based auth (DynamicTokenProvider, CustomSignatureProvider, ApiKeyProvider) was not working in static contexts **Solution:** - Add lazy initialization support to StaticAuthApplier - Add setBeanContainer() method to inject BeanContainer at runtime - Modify HttpInvocationHandler to call setBeanContainer() before applying static auth - Cache Authorization object after creation for performance **Implementation:** - StaticAuthApplier: Store RequestAuth annotation and delay Authorization creation - If no Provider: Create Authorization immediately in constructor - If Provider used: Create Authorization when setBeanContainer() is called - HttpInvocationHandler: Inject BeanContainer before calling staticApplier.apply() **Testing:** ✅ All 225 tests pass ✅ HttpInvocationHandlerTest: 7/7 tests pass ✅ No breaking changes to existing functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix: Fix authorization field mapping bug and improve code clarity Fix a bug in parameter-level authentication where API_KEY incorrectly mapped to annotation.name() instead of the "value" field of ApiKeyAuthorization. **Problem Analysis:** 1. Bug: RequestAuthResolver.getAuthorizationKey() for API_KEY returned annotation.name() (e.g., "X-API-Key"), but should return "value" to update ApiKeyAuthorization.value field 2. Root cause: Confusion between HTTP key name and Authorization object field name 3. Why tests didn't catch it: Tests only verified Setter type, not the internal field name **Solution: Introduce AuthFieldMapper (Approach 5)** - Create dedicated AuthFieldMapper class for centralized field mapping logic - Clear documentation explaining the mapping rationale - Maintains consistency with FEL Tool system's AuthorizationDestinationSetter mechanism **Changes:** 1. New file: AuthFieldMapper.java - Maps AuthType to Authorization object field names - Comprehensive Javadoc with table showing all mappings - BEARER → "token", BASIC → "username", API_KEY → "value" 2. Modified: RequestAuthResolver.java - Remove complex getAuthorizationKey() method - Use AuthFieldMapper.getParameterAuthField() for clear intent - Updated documentation 3. New tests: AuthFieldMapperTest.java (5 tests) - Verify correct field mappings for all auth types - Specifically test API_KEY returns "value" not "key" - Validate compatibility with Authorization implementations 4. Enhanced: RequestAuthResolverTest.java - Add comments explaining the bug that was found - Tests now serve as regression prevention **Key Insights:** - API Key has two concepts: * "key" field: HTTP Header/Query name (e.g., "X-API-Key") * "value" field: Actual API key value (parameter-level updates this) - AuthFieldMapper makes this distinction explicit and well-documented **Testing:** ✅ All 230 tests pass (5 new tests added) ✅ AuthFieldMapperTest: 5/5 tests pass ✅ RequestAuthResolverTest: 3/3 tests pass ✅ Maintains 100% consistency with FEL Tool system 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * docs: Fix Javadoc errors in AuthFieldMapper and RequestAuthResolver Fix Javadoc compilation errors caused by HTML5 incompatible tags and attributes. **Issues Fixed:** 1. Replace <h3> headings with <p><b> for consistency (H3 requires H2, H1 hierarchy) 2. Remove 'summary' attribute from table (not supported in HTML5) 3. Keep 'caption' element for table description **Changes:** - AuthFieldMapper.java: Replace h3 tags with p+b tags, remove summary attribute - RequestAuthResolver.java: Replace h3 tags with p+b tags **Verification:** ✅ mvn javadoc:javadoc compiles successfully ✅ All documentation formatting preserved ✅ HTML5 compliant 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * feat: Support BASIC auth field selection via name attribute for parameter-level authentication Enable parameter-level BASIC authentication to specify which field to update (username or password) using the name attribute, allowing dual-parameter authentication scenarios. **Core Changes:** 1. **AuthFieldMapper.java** - Modified getParameterAuthField() to accept nameAttribute parameter - BASIC auth: name="username" or name="password" selects field to update - Default behavior: returns "username" when name is not specified (backward compatible) - API_KEY: name specifies HTTP Header/Query name (different semantic) - BEARER: name attribute is ignored - Use StringUtils.isNotBlank() and StringUtils.equals() for string operations - Fixed Javadoc line lengths to comply with 120-character limit 2. **RequestAuthResolver.java** - Pass annotation.name() to AuthFieldMapper.getParameterAuthField() - Enables BASIC auth field selection based on name attribute 3. **RequestAuth annotation** - Enhanced Javadoc to document name attribute semantics for different auth types - Added table showing name attribute meaning per auth type - Clarified BASIC auth usage: name selects target field (username/password) **Testing:** 4. **AuthFieldMapperTest.java** (added 3 new tests, total 8 tests) - testBasicAuthFieldDefault(): Verify default returns "username" - testBasicAuthFieldExplicitUsername(): Test name="username" - testBasicAuthFieldPassword(): Test name="password" - testBasicAuthFieldInvalidName(): Verify invalid name throws exception - Updated existing tests to use new method signature 5. **Example 07 Enhancements** - TestAuthInterface: Added testBasicDynamicUsername() and testBasicDynamicBoth() - TestAuthClient: Implemented both methods with proper annotations - TestAuthServerController: Added corresponding endpoints - TestClientController: Added method invocation support - run_tests.sh: Added two new BASIC auth test cases **Usage Examples:** ```java // Method-level: Complete BASIC auth, parameter overrides username @requestauth(type = BASIC, username = "static-user", password = "static-password") String test(@requestauth(type = BASIC) String username); // Parameter-level: Separately override username and password @requestauth(type = BASIC, username = "base-user", password = "base-password") String test( @requestauth(type = BASIC, name = "username") String user, @requestauth(type = BASIC, name = "password") String pwd ); ``` **Key Design:** - name attribute has semantic overloading across auth types - BASIC: Specifies Authorization object field name - API_KEY: Specifies HTTP Header/Query name - Method-level BASIC auth must provide complete username+password - Parameter-level updates specific fields via authorizationInfo() **Validation:** ✅ All 233 tests pass ✅ Javadoc compiles without errors/warnings ✅ Code formatting complies with CodeFormatterFromIdea.xml ✅ Example 07 compiles and runs successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * refactor: Simplify StaticAuthApplier by using constructor injection for BeanContainer Remove the setBeanContainer() method and lazy initialization pattern in StaticAuthApplier, replacing it with direct constructor injection using the BeanContainer already available in AnnotationParser. **Problem:** - StaticAuthApplier used lazy initialization with setBeanContainer() called from HttpInvocationHandler - This created unnecessary complexity and runtime dependency injection - AnnotationParser already had BeanContainer available but wasn't using it - The setBeanContainer() approach required runtime checks and state management **Solution:** - Modified StaticAuthApplier constructor to accept BeanContainer parameter - AnnotationParser now passes its BeanContainer when creating StaticAuthApplier instances - Removed setBeanContainer() method entirely - Removed lazy initialization logic and state management - Simplified HttpInvocationHandler by removing BeanContainer injection code **Changes:** 1. **StaticAuthApplier.java** - Changed constructor: `StaticAuthApplier(RequestAuth, BeanContainer)` - Removed `cachedAuthorization` field, replaced with final `authorization` field - Authorization created immediately in constructor - Removed `setBeanContainer()` method - Simplified `apply()` method - no more null checks - Reduced from 118 lines to 95 lines 2. **AnnotationParser.java** - `getClassLevelAuthAppliers()`: Pass `this.beanContainer` to StaticAuthApplier - `getMethodLevelAuthAppliers()`: Pass `this.beanContainer` to StaticAuthApplier 3. **HttpInvocationHandler.java** - Removed instanceof check and setBeanContainer() call - Simplified staticApplier loop back to basic iteration **Benefits:** - ✅ Simpler design: Constructor injection instead of setter injection - ✅ Earlier error detection: Failures happen at construction time, not runtime - ✅ Immutability: Authorization is now final, thread-safe - ✅ Less code: Removed 31 lines of complexity - ✅ Clear dependencies: BeanContainer dependency explicit in constructor - ✅ Better performance: No runtime type checks or conditional initialization **Testing:** ✅ All 233 tests pass ✅ Example 07 compiles and runs successfully ✅ No behavioral changes, purely refactoring 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * refactor: Add fail-fast validation for BeanContainer in StaticAuthApplier Add notNull validation at constructor entry point and simplify createAuthorizationFromAnnotation by removing redundant null check, following the fail-fast principle. **Changes:** - Add `notNull(beanContainer, "The bean container cannot be null.")` in constructor - Remove redundant null check in createAuthorizationFromAnnotation method - BeanContainer is guaranteed non-null by AnnotationParser, validate early at entry point **Benefits:** - ✅ Fail-fast: Errors detected immediately at construction time - ✅ Clearer contract: BeanContainer is required, not optional - ✅ Simplified logic: No need for null check in private method - ✅ Consistent validation: Follows same pattern as AnnotationParser **Testing:** ✅ AuthFieldMapperTest: 8/8 tests pass ✅ No behavioral changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * docs: Add comprehensive documentation for HTTP client authentication Add detailed usage manual and principles guide for @requestauth annotation system, covering all authentication types, usage scenarios, design principles, and internals. **Documentation Structure:** 1. **HTTP_CLIENT_AUTH_USAGE.md** - User-facing usage manual - Quick start guide - Authentication types (Bearer, Basic, API Key, Custom Provider) - Usage scenarios (interface/method/parameter levels) - Best practices (security, configuration, Provider patterns) - Common Q&A - Complete examples with HTTP request formats 2. **HTTP_CLIENT_AUTH_PRINCIPLES.md** - Internal principles guide - Architecture overview with component diagrams - Core components (AnnotationParser, StaticAuthApplier, AuthFieldMapper, etc.) - Detailed workflow with execution traces - Key design decisions (constructor injection, name attribute overloading) - Consistency with FEL Tool system - Extension guide for custom authentication types **Content Highlights:** - 📖 80+ code examples covering all scenarios - 🎯 5 detailed execution flow diagrams - 📊 Component responsibility matrix - 🔧 Extension patterns for custom authentication - ⚖️ Design decision rationales - ✅ Best practices and anti-patterns **Coverage:** - All 4 authentication types: Bearer, Basic, API Key, Custom - 3-level configuration: Interface, Method, Parameter - Static vs dynamic (Provider) authentication - Field update mechanism for parameter-level auth - BASIC auth dual-parameter support with name attribute - Integration with BeanContainer and FEL Tool system **Target Audience:** - Usage Manual: Developers using HTTP client authentication - Principles Guide: Framework developers and contributors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 356190c commit c7f623a

File tree

20 files changed

+2713
-372
lines changed

20 files changed

+2713
-372
lines changed

examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestAuthClient.java

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,86 +27,105 @@
2727
@HttpProxy
2828
@RequestAddress(protocol = "http", host = "localhost", port = "8080")
2929
@RequestMapping(path = "/http-server/auth")
30-
/**
31-
* 接口级别的默认鉴权:API Key
32-
*/
3330
@RequestAuth(type = AuthType.API_KEY, name = "X-Service-Key", value = "service-default-key")
3431
public interface TestAuthClient extends TestAuthInterface {
35-
@Override
36-
@GetMapping(path = "/bearer-static")
3732
/**
3833
* 方法级别覆盖:使用 Bearer Token
3934
*/
35+
@Override
36+
@GetMapping(path = "/bearer-static")
4037
@RequestAuth(type = AuthType.BEARER, value = "static-bearer-token-12345")
4138
String testBearerStatic();
4239

43-
@Override
44-
@GetMapping(path = "/bearer-dynamic")
4540
/**
4641
* 方法级别覆盖:使用参数驱动的 Bearer Token
4742
*/
43+
@Override
44+
@GetMapping(path = "/bearer-dynamic")
4845
String testBearerDynamic(@RequestAuth(type = AuthType.BEARER) String token);
4946

50-
@Override
51-
@GetMapping(path = "/basic-static")
5247
/**
5348
* 方法级别覆盖:使用 Basic Auth
5449
*/
50+
@Override
51+
@GetMapping(path = "/basic-static")
5552
@RequestAuth(type = AuthType.BASIC, username = "admin", password = "secret123")
5653
String testBasicStatic();
5754

58-
@Override
59-
@GetMapping(path = "/apikey-header-static")
6055
/**
6156
* 方法级别覆盖:API Key 在 Header 中
6257
*/
58+
@Override
59+
@GetMapping(path = "/apikey-header-static")
6360
@RequestAuth(type = AuthType.API_KEY, name = "X-API-Key", value = "static-api-key-67890")
6461
String testApiKeyHeaderStatic();
6562

66-
@Override
67-
@GetMapping(path = "/apikey-query-static")
6863
/**
6964
* 方法级别覆盖:API Key 在 Query 参数中
7065
*/
66+
67+
@Override
68+
@GetMapping(path = "/apikey-query-static")
7169
@RequestAuth(type = AuthType.API_KEY, name = "api_key", value = "query-api-key-111", location = Source.QUERY)
7270
String testApiKeyQueryStatic();
7371

74-
@Override
75-
@GetMapping(path = "/apikey-dynamic")
7672
/**
7773
* 参数驱动的 API Key
7874
*/
75+
@Override
76+
@GetMapping(path = "/apikey-dynamic")
7977
String testApiKeyDynamic(@RequestAuth(type = AuthType.API_KEY, name = "X-Dynamic-Key") String apiKey);
8078

81-
@Override
82-
@GetMapping(path = "/dynamic-provider")
8379
/**
8480
* 方法级别覆盖:使用动态 Token Provider
8581
*/
82+
@Override
83+
@GetMapping(path = "/dynamic-provider")
8684
@RequestAuth(type = AuthType.BEARER, provider = DynamicTokenProvider.class)
8785
String testDynamicProvider();
8886

89-
@Override
90-
@GetMapping(path = "/custom-provider")
9187
/**
9288
* 方法级别覆盖:使用自定义签名 Provider
9389
*/
90+
@Override
91+
@GetMapping(path = "/custom-provider")
9492
@RequestAuth(type = AuthType.CUSTOM, provider = CustomSignatureProvider.class)
9593
String testCustomProvider();
9694

97-
@Override
98-
@GetMapping(path = "/method-override")
9995
/**
10096
* 方法级别覆盖:使用 API Key Provider
10197
*/
98+
@Override
99+
@GetMapping(path = "/method-override")
102100
@RequestAuth(type = AuthType.API_KEY, provider = ApiKeyProvider.class)
103101
String testMethodOverride();
104102

105-
@Override
106-
@GetMapping(path = "/combined-auth")
107103
/**
108104
* 组合鉴权:服务级 API Key + 用户 Token
109105
*/
106+
@Override
107+
@GetMapping(path = "/combined-auth")
110108
@RequestAuth(type = AuthType.BEARER, provider = DynamicTokenProvider.class)
111109
String testCombinedAuth(@RequestAuth(type = AuthType.API_KEY, name = "X-User-Context") String userToken);
110+
111+
/**
112+
* 参数级别的 Basic Auth - 使用参数覆盖静态配置的 username
113+
* <p>演示:方法级别提供完整的 BASIC 认证(username + password),
114+
* 参数级别动态覆盖 username 字段(不指定 name 时默认更新 username)</p>
115+
*/
116+
@Override
117+
@GetMapping(path = "/basic-dynamic-username")
118+
@RequestAuth(type = AuthType.BASIC, username = "static-user", password = "static-password")
119+
String testBasicDynamicUsername(@RequestAuth(type = AuthType.BASIC) String username);
120+
121+
/**
122+
* 参数级别的 Basic Auth - 使用参数分别覆盖 username 和 password
123+
* <p>演示:方法级别提供完整的 BASIC 认证作为基础,
124+
* 参数级别使用 name 属性明确指定要覆盖的字段(username 或 password)</p>
125+
*/
126+
@Override
127+
@GetMapping(path = "/basic-dynamic-both")
128+
@RequestAuth(type = AuthType.BASIC, username = "base-user", password = "base-password")
129+
String testBasicDynamicBoth(@RequestAuth(type = AuthType.BASIC, name = "username") String username,
130+
@RequestAuth(type = AuthType.BASIC, name = "password") String password);
112131
}

examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestAuthInterface.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,21 @@ public interface TestAuthInterface {
8686
* @return 鉴权测试结果
8787
*/
8888
String testCombinedAuth(String userToken);
89+
90+
/**
91+
* 测试参数级别的 Basic Auth - 单参数更新 username(向后兼容)。
92+
*
93+
* @param username 用户名
94+
* @return 鉴权测试结果
95+
*/
96+
String testBasicDynamicUsername(String username);
97+
98+
/**
99+
* 测试参数级别的 Basic Auth - 双参数分别更新 username 和 password。
100+
*
101+
* @param username 用户名
102+
* @param password 密码
103+
* @return 鉴权测试结果
104+
*/
105+
String testBasicDynamicBoth(String username, String password);
89106
}

examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/controller/TestClientController.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,21 @@ public Object test(@RequestQuery("type") String type, @RequestQuery("method") St
104104
*/
105105
@GetMapping(path = "/auth-test")
106106
public Object authTest(@RequestQuery("method") String method,
107-
@RequestQuery(value = "token", required = false) String token) {
107+
@RequestQuery(value = "token", required = false) String token,
108+
@RequestQuery(value = "username", required = false) String username,
109+
@RequestQuery(value = "password", required = false) String password) {
108110
switch (method) {
109111
case "bearerStatic":
110112
return authClient.testBearerStatic();
111113
case "bearerDynamic":
112114
return authClient.testBearerDynamic(token != null ? token : "dynamic-test-token");
113115
case "basicStatic":
114116
return authClient.testBasicStatic();
117+
case "basicDynamicUsername":
118+
return authClient.testBasicDynamicUsername(username != null ? username : "testuser");
119+
case "basicDynamicBoth":
120+
return authClient.testBasicDynamicBoth(username != null ? username : "testuser",
121+
password != null ? password : "testpass");
115122
case "apiKeyHeaderStatic":
116123
return authClient.testApiKeyHeaderStatic();
117124
case "apiKeyQueryStatic":

examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/controller/TestAuthServerController.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,14 @@ public String testCombinedAuth(@RequestHeader(name = "Authorization") String aut
106106
}
107107
return result;
108108
}
109+
110+
@GetMapping(path = "/basic-dynamic-username")
111+
public String testBasicDynamicUsername(@RequestHeader(name = "Authorization") String authorization) {
112+
return "Basic Dynamic Username: " + authorization;
113+
}
114+
115+
@GetMapping(path = "/basic-dynamic-both")
116+
public String testBasicDynamicBoth(@RequestHeader(name = "Authorization") String authorization) {
117+
return "Basic Dynamic Both: " + authorization;
118+
}
109119
}

examples/fit-example/07-http-client-proxy/run_tests.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ run_basic_tests() {
174174
run_test "Basic Static Auth" \
175175
"curl -s --max-time $TIMEOUT -X GET \"$BASE_URL/basic-static\" -H \"Authorization: Basic YWRtaW46c2VjcmV0MTIz\" -H \"X-Service-Key: service-default-key\"" \
176176
"Basic Static Auth: Basic YWRtaW46c2VjcmV0MTIz"
177+
178+
# testuser:static-password 的 base64 编码 (dGVzdHVzZXI6c3RhdGljLXBhc3N3b3Jk)
179+
# 参数覆盖 username: testuser,保留方法级别的 password: static-password
180+
run_test "Basic Dynamic Username" \
181+
"curl -s --max-time $TIMEOUT -X GET \"$BASE_URL/basic-dynamic-username\" -H \"Authorization: Basic dGVzdHVzZXI6c3RhdGljLXBhc3N3b3Jk\"" \
182+
"Basic Dynamic Username: Basic dGVzdHVzZXI6c3RhdGljLXBhc3N3b3Jk"
183+
184+
# testuser:testpass 的 base64 编码 (dGVzdHVzZXI6dGVzdHBhc3M=)
185+
# 参数分别覆盖 username 和 password
186+
run_test "Basic Dynamic Both" \
187+
"curl -s --max-time $TIMEOUT -X GET \"$BASE_URL/basic-dynamic-both\" -H \"Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M=\"" \
188+
"Basic Dynamic Both: Basic dGVzdHVzZXI6dGVzdHBhc3M="
177189
}
178190

179191
# API Key 测试

framework/fit/java/fit-builtin/plugins/fit-client-http/src/main/java/modelengine/fit/client/http/support/HttpProxyCreator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void onBeanContainerInitialized(BeanContainer container) {
6767
}
6868
List<Class<?>> classes = this.scan(container, packages);
6969
for (Class<?> clazz : classes) {
70-
AnnotationParser annotationParser = new AnnotationParser(this.valueFetcher);
70+
AnnotationParser annotationParser = new AnnotationParser(this.valueFetcher, container);
7171
Map<Method, HttpInfo> httpInfoMap = annotationParser.parseInterface(clazz);
7272
// Scan all interfaces, create proxy objects for each, and register them in the container.
7373
container.registry()

0 commit comments

Comments
 (0)