feat: add tenant ownership check to license file parser

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 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-22 19:09:27 +08:00
父节点 94fda7ad6e
当前提交 8f2f29170e

查看文件

@ -180,13 +180,24 @@ public class AppController {
* Used by the security center to verify license file information.
*/
@PostMapping("/license/parse")
public ResponseEntity<ApiResponse<Map<String, Object>>> parseLicenseFile(@RequestBody Map<String, String> body) {
public ResponseEntity<ApiResponse<Map<String, Object>>> parseLicenseFile(
@RequestBody Map<String, String> 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<String, Object> 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) {