package com.xuqm.push.controller; import com.xuqm.common.exception.BusinessException; import com.xuqm.common.model.ApiResponse; import com.xuqm.common.security.LicenseFileCrypto; import com.xuqm.push.entity.DeviceTokenEntity; import com.xuqm.push.service.PushAccountService; import com.xuqm.push.service.PushAppSecretClient; import com.xuqm.push.service.PushDispatcher; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping("/api/push/auth") public class PushAuthController { private final PushAccountService accountService; private final PushDispatcher pushDispatcher; private final PushAppSecretClient appSecretClient; public PushAuthController(PushAccountService accountService, PushDispatcher pushDispatcher, PushAppSecretClient appSecretClient) { this.accountService = accountService; this.pushDispatcher = pushDispatcher; this.appSecretClient = appSecretClient; } @PostMapping("/login") public ResponseEntity>> login( @RequestParam(required = false) String appKey, @RequestParam String userId, @RequestParam String userSig, @RequestParam String packageName, @RequestParam(required = false) String licenseFile, @RequestParam DeviceTokenEntity.Vendor vendor, @RequestParam String token, @RequestParam(required = false) String platform, @RequestParam(required = false) String deviceId, @RequestParam(required = false) String brand, @RequestParam(required = false) String model, @RequestParam(required = false) String osVersion, @RequestParam(required = false) String romVersion, @RequestParam(required = false) String appVersion) { String resolvedAppKey = resolveAndValidate(appKey, packageName, licenseFile); PushAccountService.LoginResult result = accountService.loginWithUserSig(resolvedAppKey, userId, userSig); pushDispatcher.registerToken(resolvedAppKey, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion, romVersion); Map response = Map.of( "pushToken", result.pushToken(), "userId", result.user().getUserId(), "appKey", appKey, "nickname", result.user().getNickname() != null ? result.user().getNickname() : "" ); return ResponseEntity.ok(ApiResponse.success(response)); } private String resolveAndValidate(String appKey, String packageName, String licenseFile) { if (hasText(licenseFile)) { LicenseFileCrypto.LicensePayload payload = LicenseFileCrypto.decrypt(licenseFile); if (!payload.matchesPackageName(packageName)) { throw new BusinessException(403, "包名与应用配置不匹配"); } return payload.appKey(); } if (!hasText(appKey)) { throw new BusinessException(400, "appKey 或 licenseFile 必须提供其中一个"); } if (packageName == null || packageName.isBlank()) { throw new BusinessException(403, "packageName is required"); } PushAppSecretClient.PlatformInfo info = appSecretClient.getPlatformInfo(appKey); boolean anyConfigured = hasText(info.androidPackageName()) || hasText(info.iosBundleId()) || hasText(info.harmonyBundleName()); if (anyConfigured) { boolean matches = packageName.equals(info.androidPackageName()) || packageName.equals(info.iosBundleId()) || packageName.equals(info.harmonyBundleName()); if (!matches) throw new BusinessException(403, "包名与应用配置不匹配"); } return appKey; } private static boolean hasText(String s) { return s != null && !s.isBlank(); } }