From 8f2f29170ec1e08207d863409f9698d38903b646 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Fri, 22 May 2026 19:09:27 +0800 Subject: [PATCH] feat: add tenant ownership check to license file parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Require @AuthenticationPrincipal tenantId in parseLicenseFile endpoint and verify the decrypted appKey belongs to the current tenant before returning license contents. Returns 403 "权限不足无法展示" for cross-tenant license files. Co-Authored-By: Claude Opus 4.7 --- .../com/xuqm/tenant/controller/AppController.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tenant-service/src/main/java/com/xuqm/tenant/controller/AppController.java b/tenant-service/src/main/java/com/xuqm/tenant/controller/AppController.java index ea1e1f8..fbdb923 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/controller/AppController.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/controller/AppController.java @@ -180,13 +180,24 @@ public class AppController { * Used by the security center to verify license file information. */ @PostMapping("/license/parse") - public ResponseEntity>> parseLicenseFile(@RequestBody Map body) { + public ResponseEntity>> parseLicenseFile( + @RequestBody Map body, + @AuthenticationPrincipal String tenantId) { String content = body.get("content"); if (content == null || content.isBlank()) { throw new BusinessException("License file content is required"); } try { LicenseFileCrypto.LicensePayload payload = LicenseFileCrypto.decrypt(content.trim()); + // Verify the license file belongs to the current tenant + try { + appService.getByAppKey(payload.appKey(), tenantId); + } catch (BusinessException e) { + if (e.getCode() == 403 || e.getCode() == 404) { + throw new BusinessException(403, "权限不足无法展示"); + } + throw e; + } Map data = new java.util.LinkedHashMap<>(); data.put("appKey", payload.appKey()); data.put("appName", payload.appName()); @@ -196,6 +207,8 @@ public class AppController { data.put("baseUrl", payload.baseUrl()); data.put("serverUrl", payload.serverUrl()); return ResponseEntity.ok(ApiResponse.success(data)); + } catch (BusinessException e) { + throw e; } catch (IllegalArgumentException e) { throw new BusinessException("Invalid license file: " + e.getMessage()); } catch (Exception e) {