Skip to content

Conversation

@lu-yg
Copy link
Collaborator

@lu-yg lu-yg commented Dec 17, 2025

English | 简体中文

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Built its own designer, fully self-validated

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

Background and solution

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • [x ] Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Added ability to identify the current tenant for multi-tenant context.
  • Improvements

    • Broader tenant-scoped data isolation applied to queries, pages, templates, updates and deletions.
    • Token extraction flow improved for more reliable authentication handling.
  • Tests

    • Tests updated to operate under tenant-scoped context.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

Adds tenant-scoping: a new LoginUserContext.getTenantId() and DefaultLoginUserContext default; mapper signatures and SQL now accept and filter by tenantId; service and tests propagate tenantId into mapper calls; SSOInterceptor token extraction adjusted.

Changes

Cohort / File(s) Summary
Login Context
base/src/main/java/com/tinyengine/it/common/context/LoginUserContext.java, base/src/main/java/com/tinyengine/it/login/config/context/DefaultLoginUserContext.java
Added getTenantId() to the login context interface; DefaultLoginUserContext implements getTenantId() and adds DEFAULT_TENANT = "1" fallback. Javadoc updated for tenant methods.
Interceptor Token Handling
base/src/main/java/com/tinyengine/it/login/config/SSOInterceptor.java
Reworked token extraction to use an intermediate authorization variable and jwtUtil.getTokenFromRequest(authorization) before validation/logging.
Mapper Interface
base/src/main/java/com/tinyengine/it/mapper/AppMapper.java
Extended mapper methods to accept tenantId (e.g., queryAllApp, queryAllAppByPage, queryAppTotal, queryAppTemplateTotal, queryAllAppTemplate, queryAppTemplateById, queryAppById, deleteAppById) to enable tenant-scoped operations.
Mapper XML Queries
base/src/main/resources/mappers/AppMapper.xml
Added tenant_id filtering to SELECT/UPDATE/DELETE statements and dynamic where clauses; introduced null-safe tenantId checks in conditions.
Service Implementations
base/src/main/java/com/tinyengine/it/service/app/impl/...
base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java
Injected LoginUserContext and passed loginUserContext.getTenantId() into mapper calls across AppServiceImpl, AppTemplateServiceImpl, PageServiceImpl, AppV1ServiceImpl, BlockServiceImpl to scope reads/changes by tenant.
Tests
base/src/test/java/com/tinyengine/it/mapper/AppMapperTest.java, base/src/test/java/com/tinyengine/it/service/app/impl/AppServiceImplTest.java
Added/updated LoginUserContext wiring/mocks and changed tests to supply tenantId to mapper calls matching updated signatures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify all AppMapper method signatures are consistently updated and callers updated accordingly.
  • Review SQL changes in AppMapper.xml for correct tenant_id predicates and null-safety in dynamic clauses.
  • Check service classes for any missed mapper calls or inconsistent tenantId propagation.
  • Confirm tests properly mock/provide tenantId and that DEFAULT_TENANT behavior is acceptable.

Poem

🐰 I nibble code and hop with glee,

Tenant fences drawn for every tree.
Queries now know where to stay,
Each carrot kept in its own tray.
Hooray for scoped fields—tea and thyme for me!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.88% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: introducing multi-tenant support with tenant context isolation, improving token handling in SSOInterceptor, and updating tests throughout the codebase.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

@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: 8

Caution

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

⚠️ Outside diff range comments (1)
base/src/main/java/com/tinyengine/it/mapper/AppMapper.java (1)

120-120: updateAppById() does not guarantee tenantId is set before execution.

The method accepts an App object, and the XML mapper (line 557) filters by tenant_id = #{tenantId}. However, MyMetaObjectHandler.updateFill() does not auto-fill tenantId during UPDATE operations, only during INSERT. PageServiceImpl.setAppHomePage() (line 442) demonstrates this risk by creating an App object with only id and homePage set, leaving tenantId null. This can cause incorrect filtering or silent UPDATE failures. Ensure all callers explicitly set App.tenantId before invoking updateAppById().

🧹 Nitpick comments (4)
base/src/main/java/com/tinyengine/it/login/config/SSOInterceptor.java (1)

51-54: Add explicit null/empty check after token extraction (optional).

While the current code safely handles invalid tokens via try-catch exception handling in validateToken(), adding an explicit check for null or empty token after extraction improves code clarity and avoids unnecessary exception handling for obvious invalid cases.

Consider adding:

String token = jwtUtil.getTokenFromRequest(authorization);
String requestURI = request.getRequestURI();

log.info("Intercepting: {}, Token: {}", requestURI, token != null ? "present" : "null");
+
+if (token == null || token.isEmpty()) {
+    log.warn("Token extraction failed or empty");
+    response.sendRedirect(SSO_SERVER);
+    return false;
+}
base/src/main/java/com/tinyengine/it/service/app/impl/AppServiceImpl.java (1)

32-32: Unused import: Tenant.

The Tenant class is imported but not used in this file.

-import com.tinyengine.it.model.entity.Tenant;
base/src/test/java/com/tinyengine/it/mapper/AppMapperTest.java (1)

39-44: Test correctly implements tenant-scoped queries and is ready for enabling.

The test accurately retrieves tenantId from LoginUserContext and passes it to the mapper method. Currently, the entire test class is @Disabled. To improve test coverage, consider:

  1. Enabling the test to verify tenant-scoping works in practice
  2. Adding test cases for tenant isolation (e.g., verify tenant A cannot access tenant B's apps)
  3. Testing edge cases where tenantId is null or invalid
base/src/main/resources/mappers/AppMapper.xml (1)

142-144: Add tenantId validation to queryAppByCondition service method or enforce it in the SQL fragment.

The AppByCondition SQL fragment makes tenantId filtering optional, and the queryAppByCondition service method does not validate that tenantId is provided. While the only current caller (createApp) validates tenantId before calling this method, the service method has no inherent protection. To prevent potential cross-tenant data access if this method is called from other code paths in the future, either add tenantId validation in the service method or make the SQL condition mandatory rather than optional.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3603e8f and 633c6c9.

📒 Files selected for processing (12)
  • base/src/main/java/com/tinyengine/it/common/context/LoginUserContext.java (1 hunks)
  • base/src/main/java/com/tinyengine/it/login/config/SSOInterceptor.java (1 hunks)
  • base/src/main/java/com/tinyengine/it/login/config/context/DefaultLoginUserContext.java (1 hunks)
  • base/src/main/java/com/tinyengine/it/mapper/AppMapper.java (4 hunks)
  • base/src/main/java/com/tinyengine/it/service/app/impl/AppServiceImpl.java (8 hunks)
  • base/src/main/java/com/tinyengine/it/service/app/impl/AppTemplateServiceImpl.java (5 hunks)
  • base/src/main/java/com/tinyengine/it/service/app/impl/PageServiceImpl.java (2 hunks)
  • base/src/main/java/com/tinyengine/it/service/app/impl/v1/AppV1ServiceImpl.java (3 hunks)
  • base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java (1 hunks)
  • base/src/main/resources/mappers/AppMapper.xml (7 hunks)
  • base/src/test/java/com/tinyengine/it/mapper/AppMapperTest.java (2 hunks)
  • base/src/test/java/com/tinyengine/it/service/app/impl/AppServiceImplTest.java (6 hunks)
🔇 Additional comments (12)
base/src/main/java/com/tinyengine/it/login/config/SSOInterceptor.java (1)

44-50: LGTM! Authorization header validation is correct.

The check for missing or empty authorization headers with appropriate redirect behavior is properly implemented.

base/src/main/java/com/tinyengine/it/service/app/impl/AppTemplateServiceImpl.java (1)

95-96: LoginUserContext dependency added for tenant-scoping.

The LoginUserContext is now injected to enable tenant-aware data access throughout the service.

base/src/main/java/com/tinyengine/it/service/app/impl/PageServiceImpl.java (2)

180-180: Tenant-scoped app retrieval added.

The app lookup is now tenant-aware by passing loginUserContext.getTenantId(). This ensures pages can only access apps within their tenant boundary.


498-498: Tenant-scoped app lookup in getAppHomePageId.

Consistent with the tenant-scoping pattern applied throughout the PR.

base/src/main/java/com/tinyengine/it/service/app/impl/v1/AppV1ServiceImpl.java (2)

146-147: LoginUserContext injected for tenant-aware app retrieval.

Enables tenant-scoping in the v1 service implementation.


282-282: Tenant-scoped app lookup in getMetaDto.

The schema generation now respects tenant boundaries by including tenantId in the app lookup.

base/src/main/java/com/tinyengine/it/service/material/impl/BlockServiceImpl.java (1)

642-642: Tenant-scoped app lookup in listNew.

The block listing now respects tenant boundaries when retrieving app information.

base/src/main/java/com/tinyengine/it/service/app/impl/AppServiceImpl.java (5)

79-80: LoginUserContext injected for tenant-scoping across all app operations.

Enables comprehensive tenant isolation for CRUD operations.


89-89: Tenant-scoped app retrieval in queryAllApp.

All apps are now filtered by tenant boundary.


112-115: Tenant-scoped pagination and total count.

Both the paginated results and the total count now respect tenant boundaries, ensuring accurate pagination within the tenant context.


177-187: Tenant-scoped queries in updateAppById.

Both the pre-update query (line 177) and post-update result retrieval (line 187) are tenant-scoped, ensuring the update operation stays within tenant boundaries.


158-159: Tenant-scoped deletion properly enforces cross-tenant isolation.

Verification confirms the mapper implementation correctly handles tenant filtering in both operations:

  • Line 158 (queryAppById): The query includes AND A.tenant_id = #{tenantId} in the WHERE clause, ensuring only apps belonging to the specified tenant are retrieved.
  • Line 159 (deleteAppById): The delete statement uses WHERE id = #{id} AND tenant_id = #{tenantId}, requiring both the app ID and tenant ID to match before deletion.

The defense-in-depth approach is properly implemented. Both database operations enforce tenant isolation at the SQL layer.

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
base/src/main/resources/mappers/AppMapper.xml (1)

529-536: Enforce tenant context in queryAppByCondition.

This method lacks tenant isolation protection. While createApp sets tenantId before calling it, the public service method doesn't enforce tenant context, unlike other queries (deleteAppById, queryAppById, queryAllApp). The AppByCondition fragment also omits tenant filtering present in other similar queries. Add tenant enforcement either by:

  • Injecting loginUserContext.getTenantId() into the App object before mapper call, or
  • Adding explicit tenant check to the AppByCondition SQL fragment
♻️ Duplicate comments (2)
base/src/main/resources/mappers/AppMapper.xml (2)

458-460: Inconsistent tenant filtering creates security risk.

This conditional tenant check allows cross-tenant data access when tenantId is null. Should be mandatory like queryAllApp on line 433.


494-496: Same inconsistent tenant filtering issue.

Apply mandatory tenant filtering here as well, consistent with other queries.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 633c6c9 and b6be083.

📒 Files selected for processing (1)
  • base/src/main/resources/mappers/AppMapper.xml (7 hunks)
🔇 Additional comments (5)
base/src/main/resources/mappers/AppMapper.xml (5)

429-435: LGTM - Mandatory tenant filtering correctly enforced.

The queryAllApp query properly enforces tenant isolation with an unconditional AND A.tenant_id = #{tenantId} clause.


509-516: LGTM - Proper tenant isolation for single-record lookup.

The queryAppById correctly enforces mandatory tenant filtering alongside the primary key lookup.


518-527: LGTM - Mandatory tenant filtering correctly applied.

The queryAppTemplateById properly enforces tenant isolation.


538-543: LGTM - Critical tenant check on DELETE operation.

The deleteAppById correctly prevents cross-tenant record deletion by enforcing mandatory tenant_id filtering.


545-553: LGTM - Critical tenant check on UPDATE operation.

The updateAppById correctly prevents cross-tenant record modification by enforcing mandatory tenant_id filtering.

@hexqi hexqi changed the title fix: modify app API feat: Add Multi-Tenant Support with Context Isolation, Improve Token Handling, and Update Tests Dec 19, 2025
@hexqi hexqi merged commit 91ebd34 into opentiny:develop Dec 19, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants