Skip to content

Conversation

tacklequestions
Copy link
Contributor

@tacklequestions tacklequestions commented Sep 22, 2025

What's the purpose of this PR

Introduce automatic OpenAPI client/server code generation support and extend user context handling to cover both standard web users and OpenAPI consumers. This ensures easier schema synchronization and more flexible authentication/authorization flows.

Which issue(s) this PR fixes:

Fixes #5462

Brief changelog

feat(openapi): Add Maven OpenAPI code generation plugin with swagger dependencies to enable automatic schema-based code generation from apollo-openapi.yaml.

feat(security): Enhance SpringSecurityUserInfoHolder to support OpenAPI consumer context.

chore(auth): Update AuthConfiguration to inject ConsumerService with lazy loading.

chore(build): Add Maven local repository to .gitignore.

Summary by CodeRabbit
New Features

Major OpenAPI expansion: apps (create/update/delete, fetch single/list/by-self/authorized, env clusters, nav tree, create-in-env, missing envs), clusters (delete), instances (by release/namespace, exclude releases), items (batch text update, branch items, diff/sync, syntax check, revert, ordered list), namespaces/app namespaces (CRUD, locks, integrity checks, associations), releases (get by id, list all/active, compare, rollback).
Consistent paginated responses and richer HTTP status handling across endpoints.
Chores

Integrated OpenAPI code generation in build.
Ignored local Maven repository.
Improved OpenAPI request attribution using consumer identity for authentication.

Summary by CodeRabbit

  • New Features

    • API requests can derive user context from OpenAPI consumer info when present, falling back to Spring Security for other requests.
  • Chores

    • Integrated OpenAPI code generation into the build to produce API interfaces/models and include generated sources.
    • Updated project build profiles to support OpenAPI generation across JDK versions.
    • Extended .gitignore to exclude local Maven repository cache.

…upport

- Add Maven OpenAPI code generation plugin with swagger dependencies now that we can use automatically generated schemas which predefined in apollo-openapi.yaml
- Enhance SpringSecurityUserInfoHolder to support OpenAPI consumer context
- Update AuthConfiguration to inject ConsumerService with lazy loading
- Add Maven local repository to .gitignore

This change enables automatic OpenAPI client/server code generation from
external spec and provides dual user context support for both regular
web users and OpenAPI consumers."
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Sep 22, 2025
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

Walkthrough

Adds Maven OpenAPI code generation and related dependencies to the Portal build, ignores the local Maven repository in VCS, and extends Spring Security user resolution to first try deriving UserInfo from an OpenAPI Consumer context via a lazily injected ConsumerService before falling back to existing UserService logic.

Changes

Cohort / File(s) Summary
Git ignore updates
/.gitignore
Add comment header and .m2/ entry to ignore the Maven local repository.
OpenAPI codegen integration (POM)
apollo-portal/pom.xml
Add apollo.openapi.spec.url property; add dependencies jackson-databind-nullable, swagger-annotations-jakarta, swagger-models-jakarta; configure openapi-generator-maven-plugin (generate-sources) and add build-helper-maven-plugin to include generated sources; add pluginManagement and JDK-specific profiles (java8, java11plus) to select generator versions.
Auth configuration wiring
apollo-portal/src/main/java/.../portal/spi/configuration/AuthConfiguration.java
Update springSecurityUserInfoHolder bean signatures in SpringSecurity auth auto-configs to accept a second parameter @Lazy ConsumerService and construct SpringSecurityUserInfoHolder(userService, consumerService).
User resolution logic
apollo-portal/src/main/java/.../portal/spi/springsecurity/SpringSecurityUserInfoHolder.java
Add ConsumerService field and lazy constructor parameter; implement getConsumerUserInfo to inspect request/OpenAPI consumer id and build UserInfo; modify getUser to prefer Consumer-derived UserInfo and fallback to Spring Security/UserService lookup with null/exception guards.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant P as Portal (Controller)
  participant UIH as SpringSecurityUserInfoHolder
  participant RC as RequestContext
  participant CS as ConsumerService
  participant US as UserService

  C->>P: HTTP request
  P->>UIH: getUser()
  UIH->>RC: Inspect request (OpenAPI path / ApolloConsumerId)
  alt OpenAPI Consumer detected
    UIH->>CS: fetch Consumer by ApolloConsumerId
    CS-->>UIH: Consumer data
    UIH-->>P: UserInfo (from Consumer)
  else Not OpenAPI or Consumer not found
    UIH->>US: find user by username
    US-->>UIH: User or null
    UIH-->>P: UserInfo (existing or default)
  end
  P-->>C: Response
Loading
sequenceDiagram
  autonumber
  participant M as Maven Lifecycle
  participant O as openapi-generator-maven-plugin
  participant FS as File System
  participant BH as build-helper-maven-plugin
  participant JC as Java Compiler

  M->>O: generate-sources (inputSpec=${apollo.openapi.spec.url})
  O->>FS: write generated sources to target/generated-sources/openapi/src/main/java
  M->>BH: add-source (include generated path)
  M->>JC: compile (includes generated sources)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nudge the build with gentle paws,
Spin specs to code with Maven laws.
In burrows of auth, I sniff the trail—
Consumer first, then users prevail.
Git ignores my stash of seeds anew—hop, hop! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues Check ❓ Inconclusive The PR clearly implements OpenAPI codegen integration (pom.xml) and enhances SpringSecurityUserInfoHolder to support OpenAPI consumer context, which addresses build and authentication aspects related to issue #5462, but the provided diff does not include the generated API controllers, DTOs, unified response wrappers, pagination validation, or a centralized permission exception handler, so I cannot verify the core API refactor checklist items (RESTful URL redesign, explicit HTTP methods, DTO/response standardization, unified pagination validation, and structured permission errors) from issue #5462. Please include the generated controller and DTO sources or a short mapping showing how each checklist item from issue #5462 (resource-oriented URLs and HTTP methods, DTOs and unified response types, pagination validation, and permission exception handling) is satisfied, or attach the generated sources/artifacts so those items can be verified.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title is a concise, single-sentence summary that accurately highlights the primary changes—adding OpenAPI code generation and enhancing user context support—which matches the pom.xml build changes and the SpringSecurity-related updates in the diff; it is specific, avoids noise, and is suitable for a changelog.
Out of Scope Changes Check ✅ Passed All visible changes (OpenAPI generation configuration in pom.xml, lazy injection of ConsumerService in auth config, changes to SpringSecurityUserInfoHolder, and the .gitignore addition) are relevant to adding OpenAPI generation and improving OpenAPI consumer user context; the .gitignore addition is a minor build-related chore and not an unrelated functional change.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

github-actions bot commented Sep 22, 2025

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@tacklequestions
Copy link
Contributor Author

I have read the CLA Document and I hereby sign the CLA

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)

113-122: Avoid NPE when authentication/principal is absent

SecurityContextHolder.getContext().getAuthentication() may be null. Add a guard.

Apply this diff:

-  private String getCurrentUsername() {
-    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+  private String getCurrentUsername() {
+    if (SecurityContextHolder.getContext() == null
+        || SecurityContextHolder.getContext().getAuthentication() == null
+        || SecurityContextHolder.getContext().getAuthentication().getPrincipal() == null) {
+      return "anonymousUser";
+    }
+    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
     if (principal instanceof UserDetails) {
       return ((UserDetails) principal).getUsername();
     }
     if (principal instanceof Principal) {
       return ((Principal) principal).getName();
     }
     return String.valueOf(principal);
   }
🧹 Nitpick comments (1)
apollo-portal/pom.xml (1)

217-257: Consider gating codegen behind a Maven profile to avoid network/CPU cost on default builds

If developers/CI don’t always need regenerated sources, bind generation under a profile (e.g., -Popenapi-codegen) and check generated sources into target only. This reduces flaky builds in restricted networks.

Example profile (outline only):

-			<plugin>
+			<plugin>
 				<groupId>org.openapitools</groupId>
 				<artifactId>openapi-generator-maven-plugin</artifactId>
 				<version>7.15.0</version>
-				<executions>
+				<executions>
 					<execution>
 						<id>generate-openapi-sources</id>
-						<phase>generate-sources</phase>
+						<phase>generate-sources</phase>
 						<goals>
 							<goal>generate</goal>
 						</goals>
 						<configuration>
 							...
 						</configuration>
 					</execution>
 				</executions>
 			</plugin>
+            <!-- Wrap the execution with a profile if you prefer opt-in generation -->
+            <!-- <profiles>
+              <profile>
+                <id>openapi-codegen</id>
+                <build>
+                  <plugins>... openapi plugin here ...</plugins>
+                </build>
+              </profile>
+            </profiles> -->
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa881a and db0c14f.

📒 Files selected for processing (4)
  • .gitignore (1 hunks)
  • apollo-portal/pom.xml (3 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (5 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/UserInfo.java (1)
  • UserInfo (19-79)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
  • SpringSecurityUserInfoHolder (35-123)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (10)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (3)

35-35: LGTM: lazy injection import

@Lazy import is appropriate for deferring ConsumerService initialization.


58-83: LGTM: new OpenAPI-related imports

Imports align with new OpenAPI consumer/user-context integration.


87-90: Verify security model for OpenAPI path bypass

/openapi/** is in BY_PASS_URLS. Confirm your OpenAPI auth filter still runs and enforces consumer checks even when requests are permitted by Spring Security, and that method/endpoint-level authorization is not weakened.

apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (4)

19-28: LGTM: request/Principal/context imports

Imports look correct for request-context access.


29-34: LGTM: OpenAPI Consumer types and portal types

New domain imports align with the added consumer-based resolution.


41-45: Constructor OK, but allow null consumer service

With the config updated to make ConsumerService optional, consumerService can be null at runtime. Ensure downstream code guards for null before usage (see next comment’s diff).


49-65: Precedence change: consumer context before Spring Security

Flow reads well: prefer OpenAPI consumer identity, then fall back to Spring Security. Ensure this precedence is intentional for audit/attribution.

apollo-portal/pom.xml (2)

258-278: LGTM on adding build-helper to include generated sources

The path matches the generator’s output layout and will make IDEs/compilers see generated interfaces without extra config.


217-257: Align OpenAPI generator with Spring Boot version and enable spec validation

  • In apollo-portal/pom.xml plugin config, under <configOptions>, add
    <useSpringBoot3>${openapi.useSpringBoot3}</useSpringBoot3>
    and
    <useJakartaEe>${openapi.useJakartaEe}</useJakartaEe>.
  • Change <skipValidateSpec>true</skipValidateSpec> to <skipValidateSpec>false</skipValidateSpec> (or keep skip but add a CI check to validate the spec).
  • In your <properties> section, define defaults:
    <openapi.useSpringBoot3>false</openapi.useSpringBoot3>
    <openapi.useJakartaEe>false</openapi.useJakartaEe>
  • Verify that openapi-generator-maven-plugin 7.15.0 supports these flags and that your project is on Spring Boot 3 / Jakarta EE 9+ before enabling them.
.gitignore (1)

30-32: Confirm intent for .m2 in .gitignore — ripgrep returned no matches for maven.repo.local in the repo; if you don't use a project-local Maven repo, remove the top-level .m2 entry or narrow it to .m2/repository to avoid ignoring unrelated files.

<artifactId>apollo-portal</artifactId>
<name>Apollo Portal</name>
<properties>
<apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Avoid fetching OpenAPI spec from a moving remote URL during build (reproducibility/supply‑chain)

Pointing inputSpec to a raw GitHub URL on main makes builds network‑ and branch‑dependent. Prefer vendoring the spec in-repo (with review) and allow remote override via -D when needed or pin to a commit SHA.

Apply this minimal change to default to a local spec (override via -Dapollo.openapi.spec.url=... when needed):

-		<apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
+		<apollo.openapi.spec.url>${project.basedir}/src/main/openapi/apollo-openapi.yaml</apollo.openapi.spec.url>

🏁 Script executed:

#!/bin/bash
# Verify a local spec exists (adjust path if different)
if [ -f "apollo-portal/src/main/openapi/apollo-openapi.yaml" ]; then
  echo "Local OpenAPI spec present."
else
  echo "Local OpenAPI spec missing. Please add it or document -Dapollo.openapi.spec.url usage."
fi

Length of output: 86


Vendor the OpenAPI spec and stop using a moving raw‑GitHub URL as the default

Local spec missing: apollo-portal/src/main/openapi/apollo-openapi.yaml (verification output). Do one of the following:

  • Add the spec to apollo-portal/src/main/openapi/apollo-openapi.yaml and update apollo-portal/pom.xml to default to it (allow override with -Dapollo.openapi.spec.url=...). Minimal diff:
-		<apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
+		<apollo.openapi.spec.url>${project.basedir}/src/main/openapi/apollo-openapi.yaml</apollo.openapi.spec.url>
  • Or, if not vendoring, pin the raw GitHub URL to a commit SHA (not main) and still support -D override.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
<apollo.openapi.spec.url>${project.basedir}/src/main/openapi/apollo-openapi.yaml</apollo.openapi.spec.url>
🤖 Prompt for AI Agents
In apollo-portal/pom.xml around line 30 the OpenAPI spec default points to a
moving raw GitHub URL which causes build verification to fail because
apollo-portal/src/main/openapi/apollo-openapi.yaml is missing; fix by vendoring
the spec or pinning the URL: add the OpenAPI file to
apollo-portal/src/main/openapi/apollo-openapi.yaml and change the pom default to
use that local file path (but keep property override via
-Dapollo.openapi.spec.url=...), or if you prefer not to vendor, change the URL
to the raw.githubusercontent.com link pinned to a specific commit SHA and ensure
the pom still allows -Dapollo.openapi.spec.url to override the default.

Comment on lines +48 to +62
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>2.2.22</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models-jakarta</artifactId>
<version>2.2.22</version>
</dependency>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Check jakarta vs javax alignment with your Spring Boot baseline

Adding swagger-annotations-jakarta/models-jakarta is fine if targeting Boot 3 (Jakarta EE 9). If the portal is still on Boot 2, ensure the generator and annotations don’t introduce jakarta.validation imports. Mismatch here will fail compilation at best and runtime at worst.

Run to detect baseline and validation imports:

If on Boot 3, set the generator option useSpringBoot3/useJakartaEe (see next comment). If on Boot 2, keep javax.* generation.


🏁 Script executed:

#!/bin/bash
echo "Spring Boot starters:"
rg -nP '\bspring-boot[-:]' -C1
echo "Validation packages used in sources:"
rg -nP '\b(jakarta|javax)\.validation\.' -g '!**/target/**' -C1

Length of output: 12904


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find occurrences of 'spring-boot.version' (property, references)..."
rg -n --hidden --no-ignore -S 'spring-boot.version' || true
rg -n --hidden --no-ignore -S '<spring-boot.version>.*</spring-boot.version>' || true

echo
echo "2) Show root pom.xml head (first 300 lines) to find <properties> / parent info..."
if [ -f pom.xml ]; then
  sed -n '1,300p' pom.xml || true
else
  echo "pom.xml not found at repository root"
fi

echo
echo "3) Find where spring-boot-dependencies / spring-boot-starter-parent are referenced (context)..."
rg -n --hidden --no-ignore -S '<artifactId>spring-boot-dependencies</artifactId>|<artifactId>spring-boot-starter-parent</artifactId>' -C3 || true

echo
echo "4) Show apollo-portal/pom.xml (first 200 lines) to confirm added dependencies..."
if [ -f apollo-portal/pom.xml ]; then
  sed -n '1,200p' apollo-portal/pom.xml || true
else
  echo "apollo-portal/pom.xml not found"
fi

echo
echo "5) Search for spring-boot-starter-validation usages..."
rg -n --hidden --no-ignore -S 'spring-boot-starter-validation' || true

echo
echo "6) Search for javax.validation and jakarta.validation imports/usages in sources (exclude target)..."
rg -n --hidden --no-ignore -S 'import\s+javax\.validation\.' --glob '!**/target/**' || true
rg -n --hidden --no-ignore -S 'import\s+jakarta\.validation\.' --glob '!**/target/**' || true
rg -n --hidden --no-ignore -S '\b(jakarta|javax)\.validation\b' --glob '!**/target/**' || true

echo
echo "7) Confirm presence of swagger-annotations-jakarta / swagger-models-jakarta in pom(s)..."
rg -n --hidden --no-ignore -S 'swagger-annotations-jakarta|swagger-models-jakarta' || true

echo
echo "8) Search for OpenAPI generator/gradle plugin config that might control javax/jakarta generation (useSpringBoot3/useJakartaEe)..."
rg -n --hidden --no-ignore -S 'openapi|openapi-generator|useSpringBoot3|useJakartaEe|useJakarta' -C2 || true

Length of output: 158856


Action required — fix jakarta/javax mismatch (Spring Boot 2.7.11 vs jakarta swagger artifacts)

Root POM uses Spring Boot 2.7.11 (pom.xml:67). apollo-portal/pom.xml currently depends on swagger-annotations-jakarta and swagger-models-jakarta (apollo-portal/pom.xml ~lines 49–60) and contains the openapi-generator plugin (apollo-portal/pom.xml ~lines 219–244).

  • If you remain on Spring Boot 2: replace the jakarta swagger artifacts with the non‑Jakarta equivalents (io.swagger.core.v3:swagger-annotations and io.swagger.core.v3:swagger-models) and ensure the openapi-generator does not enable useSpringBoot3/useJakartaEe.
  • If you intend to move to Spring Boot 3: update the root <spring-boot.version> to 3.x and set the openapi-generator additionalProperties useSpringBoot3/useJakartaEe=true (then keep the jakarta artifacts).

Files to change: pom.xml (root), apollo-portal/pom.xml (dependencies + openapi-generator plugin).

Comment on lines +112 to 114
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make ConsumerService optional to avoid bean creation failures across profiles

In environments without OpenAPI, a hard dependency on ConsumerService will fail bean creation. Make it optional and pass null to the holder.

Apply this diff:

-    public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
-      return new SpringSecurityUserInfoHolder(userService, consumerService);
+    public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy java.util.Optional<ConsumerService> consumerService) {
+      return new SpringSecurityUserInfoHolder(userService, consumerService.orElse(null));
     }

If you prefer imports, also add:

+import java.util.Optional;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService);
}
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy java.util.Optional<ConsumerService> consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService.orElse(null));
}
🤖 Prompt for AI Agents
In
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java
around lines 112-114, the ConsumerService parameter is a hard dependency causing
bean creation failures in profiles without OpenAPI; make ConsumerService
optional by annotating the parameter as nullable (e.g., add @Nullable to the
@Lazy ConsumerService parameter) and update imports to include
org.springframework.lang.Nullable so the method signature becomes something like
springSecurityUserInfoHolder(UserService userService, @Lazy @Nullable
ConsumerService consumerService) and continue passing the consumerService (which
may be null) into the SpringSecurityUserInfoHolder constructor.

Comment on lines +216 to 218
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Same optional injection for LDAP profile

Mirror the optional ConsumerService to prevent failures when OpenAPI is not present under LDAP profile.

Apply this diff:

-    public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
-      return new SpringSecurityUserInfoHolder(userService, consumerService);
+    public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy java.util.Optional<ConsumerService> consumerService) {
+      return new SpringSecurityUserInfoHolder(userService, consumerService.orElse(null));
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService);
}
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy java.util.Optional<ConsumerService> consumerService) {
return new SpringSecurityUserInfoHolder(userService, consumerService.orElse(null));
}
🤖 Prompt for AI Agents
In
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java
around lines 216-218, the ConsumerService parameter is eagerly required which
can cause failures under the LDAP profile when OpenAPI/ConsumerService is
absent; make the ConsumerService injection optional (mirror other optional
injections) by annotating the parameter to allow null/absent (e.g., add
@Nullable or use @Autowired(required = false)) and adjust constructor invocation
accordingly so Spring will pass null when ConsumerService is not present.

Comment on lines +70 to +108
private UserInfo getConsumerUserInfo() {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return null;
}

HttpServletRequest request = attributes.getRequest();
String requestURI = request.getRequestURI();

// 只对OpenAPI请求处理Consumer用户信息
if (!requestURI.startsWith("/openapi/")) {
return null;
}

// 获取Consumer ID
Object consumerIdObj = request.getAttribute("ApolloConsumerId");
if (consumerIdObj == null) {
return null;
}

long consumerId = Long.parseLong(consumerIdObj.toString());
Consumer consumer = consumerService.getConsumerByConsumerId(consumerId);
if (consumer == null) {
return null;
}

// 构建基于Consumer的用户信息
UserInfo userInfo = new UserInfo();
userInfo.setUserId(consumer.getOwnerName());
userInfo.setName(consumer.getName());
userInfo.setEmail(consumer.getOwnerEmail());

return userInfo;
} catch (Exception e) {
// 如果获取Consumer信息失败,返回null,让系统回退到默认方式
return null;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Harden consumer-based resolution (context path, null service, parsing, userId safety)

Guard against common deployment/runtime pitfalls.

Apply this diff:

   private UserInfo getConsumerUserInfo() {
     try {
+      // Optional dependency might be absent when OpenAPI is not enabled
+      if (consumerService == null) {
+        return null;
+      }
       ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
       if (attributes == null) {
         return null;
       }

       HttpServletRequest request = attributes.getRequest();
       String requestURI = request.getRequestURI();
+      String contextPath = request.getContextPath();
+      if (contextPath != null && !contextPath.isEmpty() && requestURI.startsWith(contextPath)) {
+        requestURI = requestURI.substring(contextPath.length());
+      }

       // 只对OpenAPI请求处理Consumer用户信息
-      if (!requestURI.startsWith("/openapi/")) {
+      if (!requestURI.startsWith("/openapi/")) {
         return null;
       }

       // 获取Consumer ID
       Object consumerIdObj = request.getAttribute("ApolloConsumerId");
       if (consumerIdObj == null) {
         return null;
       }
-
-      long consumerId = Long.parseLong(consumerIdObj.toString());
+      String consumerIdStr = String.valueOf(consumerIdObj).trim();
+      if (consumerIdStr.isEmpty()) {
+        return null;
+      }
+      long consumerId;
+      try {
+        consumerId = Long.parseLong(consumerIdStr);
+      } catch (NumberFormatException ignore) {
+        return null;
+      }
       Consumer consumer = consumerService.getConsumerByConsumerId(consumerId);
       if (consumer == null) {
         return null;
       }

       // 构建基于Consumer的用户信息
       UserInfo userInfo = new UserInfo();
-      userInfo.setUserId(consumer.getOwnerName());
+      String ownerName = consumer.getOwnerName();
+      if (ownerName == null || ownerName.isEmpty()) {
+        ownerName = "consumer-" + consumerId;
+      }
+      userInfo.setUserId(ownerName);
       userInfo.setName(consumer.getName());
       userInfo.setEmail(consumer.getOwnerEmail());

       return userInfo;
     } catch (Exception e) {
       // 如果获取Consumer信息失败,返回null,让系统回退到默认方式
       return null;
     }
   }

Optional: add debug-level logging for troubleshooting instead of swallowing all exceptions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private UserInfo getConsumerUserInfo() {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return null;
}
HttpServletRequest request = attributes.getRequest();
String requestURI = request.getRequestURI();
// 只对OpenAPI请求处理Consumer用户信息
if (!requestURI.startsWith("/openapi/")) {
return null;
}
// 获取Consumer ID
Object consumerIdObj = request.getAttribute("ApolloConsumerId");
if (consumerIdObj == null) {
return null;
}
long consumerId = Long.parseLong(consumerIdObj.toString());
Consumer consumer = consumerService.getConsumerByConsumerId(consumerId);
if (consumer == null) {
return null;
}
// 构建基于Consumer的用户信息
UserInfo userInfo = new UserInfo();
userInfo.setUserId(consumer.getOwnerName());
userInfo.setName(consumer.getName());
userInfo.setEmail(consumer.getOwnerEmail());
return userInfo;
} catch (Exception e) {
// 如果获取Consumer信息失败,返回null,让系统回退到默认方式
return null;
}
}
private UserInfo getConsumerUserInfo() {
try {
// Optional dependency might be absent when OpenAPI is not enabled
if (consumerService == null) {
return null;
}
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return null;
}
HttpServletRequest request = attributes.getRequest();
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
if (contextPath != null && !contextPath.isEmpty() && requestURI.startsWith(contextPath)) {
requestURI = requestURI.substring(contextPath.length());
}
// 只对OpenAPI请求处理Consumer用户信息
if (!requestURI.startsWith("/openapi/")) {
return null;
}
// 获取Consumer ID
Object consumerIdObj = request.getAttribute("ApolloConsumerId");
if (consumerIdObj == null) {
return null;
}
String consumerIdStr = String.valueOf(consumerIdObj).trim();
if (consumerIdStr.isEmpty()) {
return null;
}
long consumerId;
try {
consumerId = Long.parseLong(consumerIdStr);
} catch (NumberFormatException ignore) {
return null;
}
Consumer consumer = consumerService.getConsumerByConsumerId(consumerId);
if (consumer == null) {
return null;
}
// 构建基于Consumer的用户信息
UserInfo userInfo = new UserInfo();
String ownerName = consumer.getOwnerName();
if (ownerName == null || ownerName.isEmpty()) {
ownerName = "consumer-" + consumerId;
}
userInfo.setUserId(ownerName);
userInfo.setName(consumer.getName());
userInfo.setEmail(consumer.getOwnerEmail());
return userInfo;
} catch (Exception e) {
// 如果获取Consumer信息失败,返回null,让系统回退到默认方式
return null;
}
}
🤖 Prompt for AI Agents
In
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java
around lines 70-108, tighten the consumer-based resolution: ensure request and
requestURI are non-null before checking the path and use the context path when
matching (e.g. compare request.getContextPath() + "/openapi/" or check contains)
to avoid false negatives; guard against a null consumerService and return null
early if it’s not available; protect Long.parseLong with a NumberFormatException
catch and validate the ApolloConsumerId attribute is a string/number before
parsing; ensure consumer.getOwnerName/getOwnerEmail can be null by using safe
fallbacks (e.g. use String.valueOf(consumer.getId()) or empty string) when
setting userId/name/email; and replace the broad swallow of exceptions with
debug-level logging of the exception before returning null for safer
troubleshooting.

- Refractor the pom.xml to add java 8 support of openapi-generator plugin
- Refractor the pom.xml to add java 8 support of openapi-generator plugin
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apollo-portal/pom.xml (3)

140-172: Make generator’s EE/Boot choices explicit and tighten outputs

Set generator flags explicitly to avoid accidental jakarta generation on Boot 2, and reduce churn in outputs.

Proposed adjustments inside :

   <configuration>
     <inputSpec>${apollo.openapi.spec.url}</inputSpec>
     <generatorName>spring</generatorName>
     <output>${project.build.directory}/generated-sources/openapi</output>
     <apiPackage>com.ctrip.framework.apollo.openapi.api</apiPackage>
     <modelPackage>com.ctrip.framework.apollo.openapi.model</modelPackage>
     <invokerPackage>com.ctrip.framework.apollo.openapi.invoker</invokerPackage>
     <configOptions>
       <interfaceOnly>true</interfaceOnly>
       <useTags>true</useTags>
       <dateLibrary>java8</dateLibrary>
+      <!-- Set these to match your Spring Boot baseline -->
+      <useSpringBoot3>false</useSpringBoot3>
+      <useJakartaEe>false</useJakartaEe>
+      <!-- Optional hygiene -->
+      <generateSupportingFiles>false</generateSupportingFiles>
+      <useBeanValidation>true</useBeanValidation>
     </configOptions>
-    <skipValidateSpec>true</skipValidateSpec>
+    <!-- Prefer validating in CI; see next comment -->
+    <skipValidateSpec>false</skipValidateSpec>
   </configuration>

If the project is on Boot 3, flip both booleans to true.
To be safe, please verify with the effective POM on both JDK 8 and 11+.


166-167: Don’t skip OpenAPI spec validation by default

Skipping validation hides spec issues until runtime. Enable validation by default and, if needed, add a developer-only profile to skip locally.

Example:

-        <skipValidateSpec>true</skipValidateSpec>
+        <skipValidateSpec>false</skipValidateSpec>

Optionally add a profile:

+  <profiles>
+    <profile>
+      <id>dev-skip-openapi-validate</id>
+      <properties>
+        <openapi.skip.validate>true</openapi.skip.validate>
+      </properties>
+    </profile>
+  </profiles>

and reference it as ${openapi.skip.validate}.


281-319: Consolidate OpenAPI plugin version; verify effective POM

  • java8 profile pin to 6.6.0 is fine; avoid duplicating 7.15.0 in java11plus — either remove the redundant profile or centralize the version in a property (e.g., <openapi-generator.version>) and reference it.
  • Verify that executions declared in top-level still apply under the java8 profile by running locally:
    mvn help:effective-pom | sed -n '/openapi-generator-maven-plugin</artifactId>/,/</plugin>/p'
  • File: apollo-portal/pom.xml (≈ lines 281–319). Sandbox lacked mvn (mvn: command not found); local verification required.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c478ce1 and 52689d8.

📒 Files selected for processing (1)
  • apollo-portal/pom.xml (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (6)
apollo-portal/pom.xml (6)

251-256: Plugin declaration looks good

Declaring the plugin here ensures the managed execution runs. No issues.


257-277: Marking generated sources is fine; exclude from checks/formatters

Good call adding build-helper. Ensure Checkstyle/Spotless/PMD exclude ${project.build.directory}/generated-sources/openapi/** to avoid noisy diffs and failures.


30-33: Avoid remote/main URL for inputSpec — vendor locally or pin to a commit SHA

Defaulting to a moving raw GitHub URL makes builds non‑reproducible and network‑fragile. Prefer a checked‑in spec (override via -D when needed) or pin to a specific commit SHA.

Apply one of the following minimal diffs:

-        <apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
+        <apollo.openapi.spec.url>${project.basedir}/src/main/openapi/apollo-openapi.yaml</apollo.openapi.spec.url>

Or, if you won’t vendor the spec, at least pin the URL:

-        <apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/main/apollo-openapi.yaml</apollo.openapi.spec.url>
+        <!-- TODO: replace <commit-sha> with the exact commit -->
+        <apollo.openapi.spec.url>https://raw.githubusercontent.com/tacklequestions/apollo-openapi/<commit-sha>/apollo-openapi.yaml</apollo.openapi.spec.url>

48-62: Jakarta vs javax alignment with Spring Boot baseline

These jakarta Swagger artifacts will pull jakarta.* types. If the portal remains on Spring Boot 2.x (javax.*), switch to non‑Jakarta artifacts and set generator flags; if on Boot 3.x, keep jakarta and set useSpringBoot3/useJakartaEe accordingly.

Boot 2.x option (swap artifacts):

-        <dependency>
-            <groupId>io.swagger.core.v3</groupId>
-            <artifactId>swagger-annotations-jakarta</artifactId>
-            <version>2.2.22</version>
-        </dependency>
-        <dependency>
-            <groupId>io.swagger.core.v3</groupId>
-            <artifactId>swagger-models-jakarta</artifactId>
-            <version>2.2.22</version>
-        </dependency>
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>2.2.22</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>2.2.22</version>
+        </dependency>

Then in the generator config (see next comment) set:

  • useSpringBoot3=false
  • useJakartaEe=false

If you’re moving to Boot 3.x, keep current deps and set:

  • useSpringBoot3=true
  • useJakartaEe=true

Also confirm whether jackson-databind-nullable is actually referenced by generated code; if not, drop it.


140-172: Verify JDK matrix behavior end-to-end — Maven missing in verification environment

mvn was not available in the environment you used (output showed Java 17 and "mvn: command not found"); I couldn't confirm the plugin-selection behaviour. Run these local checks and paste the output:

#!/bin/bash
set -euo pipefail
echo "Java: $(java -version 2>&1 | head -n1 || true)"
echo
echo "POM files containing the openapi-generator plugin:"
grep -RIn --line-number "<artifactId>openapi-generator-maven-plugin</artifactId>" || true
echo
echo "Print <plugin>...</plugin> blocks that contain that artifactId:"
for f in $(grep -RIl "<artifactId>openapi-generator-maven-plugin</artifactId>" || true); do
  echo "---- $f ----"
  sed -n '/<plugin>/,/<\/plugin>/p' "$f"
done
echo
echo "Profiles / activations referencing specific JDKs:"
grep -RIn --line-number "<jdk>" || true
echo
echo "Check for properties or variables referencing the plugin version (e.g. 6.6.0 / 7.15.0):"
grep -RIn --line-number "6\.6\.0\|7\.15\.0\|openapi-generator.*version" || true
echo
echo "Also inspect apollo-portal/pom.xml at lines ~140-172 and ~281-319."

Ensure the results show:

  • On JDK 1.8: plugin version 6.6.0 is selected and executions (generate goal) are present.
  • On JDK 11+: plugin version 7.15.0 is selected.

If mvn is available in CI but not locally, run mvn -q help:effective-pom on the same JDKs and confirm the effective-pom reflects the expected versions/executions.


48-52: Confirm need for jackson-databind-nullable

Keep only if generated models use org.openapitools.jackson.nullable.JsonNullable; otherwise remove to reduce surface area.

Location: apollo-portal/pom.xml:48-52

Quick check (locally): mvn -DskipTests generate-sources && rg -n --hidden --no-ignore "org.openapitools.jackson.nullable|JsonNullable" target/generated-sources/openapi -S || true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:L This PR changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Refactor] 统一 Apollo-portal API 设计规范
1 participant