-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
feat(openapi): Add OpenAPI code generation and enhance user context support #5466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(openapi): Add OpenAPI code generation and enhance user context support #5466
Conversation
…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."
WalkthroughAdds 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
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
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)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests
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. Comment |
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA |
There was a problem hiding this 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 buildsIf 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
📒 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 deferringConsumerService
initialization.
58-83
: LGTM: new OpenAPI-related importsImports 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 importsImports look correct for request-context access.
29-34
: LGTM: OpenAPI Consumer types and portal typesNew domain imports align with the added consumer-based resolution.
41-45
: Constructor OK, but allow null consumer serviceWith 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 SecurityFlow 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 sourcesThe 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 formaven.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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.
<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.
<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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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).
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) { | ||
return new SpringSecurityUserInfoHolder(userService, consumerService); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
public UserInfoHolder springSecurityUserInfoHolder(UserService userService, @Lazy ConsumerService consumerService) { | ||
return new SpringSecurityUserInfoHolder(userService, consumerService); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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
There was a problem hiding this 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 outputsSet 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 defaultSkipping 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
📒 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 goodDeclaring the plugin here ensures the managed execution runs. No issues.
257-277
: Marking generated sources is fine; exclude from checks/formattersGood 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 SHADefaulting 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 baselineThese 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 environmentmvn 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-nullableKeep 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
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
Chores