2026-05-14 23:40:35 +08:00
|
|
|
package com.xuqm.push.controller;
|
|
|
|
|
|
2026-05-22 16:41:17 +08:00
|
|
|
import com.xuqm.common.exception.BusinessException;
|
2026-05-14 23:40:35 +08:00
|
|
|
import com.xuqm.common.model.ApiResponse;
|
2026-05-22 16:47:30 +08:00
|
|
|
import com.xuqm.common.security.LicenseFileCrypto;
|
2026-05-14 23:40:35 +08:00
|
|
|
import com.xuqm.push.entity.DeviceTokenEntity;
|
|
|
|
|
import com.xuqm.push.service.PushAccountService;
|
2026-05-22 16:41:17 +08:00
|
|
|
import com.xuqm.push.service.PushAppSecretClient;
|
2026-05-14 23:40:35 +08:00
|
|
|
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;
|
2026-05-22 16:41:17 +08:00
|
|
|
private final PushAppSecretClient appSecretClient;
|
2026-05-14 23:40:35 +08:00
|
|
|
|
2026-05-22 16:41:17 +08:00
|
|
|
public PushAuthController(PushAccountService accountService, PushDispatcher pushDispatcher,
|
|
|
|
|
PushAppSecretClient appSecretClient) {
|
2026-05-14 23:40:35 +08:00
|
|
|
this.accountService = accountService;
|
|
|
|
|
this.pushDispatcher = pushDispatcher;
|
2026-05-22 16:41:17 +08:00
|
|
|
this.appSecretClient = appSecretClient;
|
2026-05-14 23:40:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PostMapping("/login")
|
|
|
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
2026-05-22 16:47:30 +08:00
|
|
|
@RequestParam(required = false) String appKey,
|
2026-05-14 23:40:35 +08:00
|
|
|
@RequestParam String userId,
|
|
|
|
|
@RequestParam String userSig,
|
2026-05-22 16:41:17 +08:00
|
|
|
@RequestParam String packageName,
|
2026-05-22 16:47:30 +08:00
|
|
|
@RequestParam(required = false) String licenseFile,
|
2026-05-14 23:40:35 +08:00
|
|
|
@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,
|
2026-06-26 12:41:49 +08:00
|
|
|
@RequestParam(required = false) String romVersion,
|
2026-05-14 23:40:35 +08:00
|
|
|
@RequestParam(required = false) String appVersion) {
|
|
|
|
|
|
2026-05-22 16:47:30 +08:00
|
|
|
String resolvedAppKey = resolveAndValidate(appKey, packageName, licenseFile);
|
|
|
|
|
PushAccountService.LoginResult result = accountService.loginWithUserSig(resolvedAppKey, userId, userSig);
|
2026-06-26 12:41:49 +08:00
|
|
|
pushDispatcher.registerToken(resolvedAppKey, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion, romVersion);
|
2026-05-14 23:40:35 +08:00
|
|
|
|
|
|
|
|
Map<String, Object> 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));
|
|
|
|
|
}
|
2026-05-22 16:41:17 +08:00
|
|
|
|
2026-05-22 16:47:30 +08:00
|
|
|
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 必须提供其中一个");
|
|
|
|
|
}
|
2026-05-22 16:41:17 +08:00
|
|
|
if (packageName == null || packageName.isBlank()) {
|
|
|
|
|
throw new BusinessException(403, "packageName is required");
|
|
|
|
|
}
|
|
|
|
|
PushAppSecretClient.PlatformInfo info = appSecretClient.getPlatformInfo(appKey);
|
2026-05-22 16:47:30 +08:00
|
|
|
boolean anyConfigured = hasText(info.androidPackageName()) || hasText(info.iosBundleId()) || hasText(info.harmonyBundleName());
|
2026-05-22 16:41:17 +08:00
|
|
|
if (anyConfigured) {
|
2026-05-22 16:47:30 +08:00
|
|
|
boolean matches = packageName.equals(info.androidPackageName())
|
|
|
|
|
|| packageName.equals(info.iosBundleId())
|
|
|
|
|
|| packageName.equals(info.harmonyBundleName());
|
2026-05-22 16:41:17 +08:00
|
|
|
if (!matches) throw new BusinessException(403, "包名与应用配置不匹配");
|
|
|
|
|
}
|
2026-05-22 16:47:30 +08:00
|
|
|
return appKey;
|
2026-05-22 16:41:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static boolean hasText(String s) { return s != null && !s.isBlank(); }
|
2026-05-14 23:40:35 +08:00
|
|
|
}
|