support multi-app device registration per device
- Add composite unique constraint (app_key, device_id) on DeviceEntity - Remove global unique constraint from device_id column - Update DeviceRepository: findByAppKeyAndDeviceId returns Optional, findByDeviceId returns List for multi-app lookups - Update DeviceService.register/verify to scope lookups by appKey so same physical device can register independently for each app - Update LicenseInternalController.getDevice to return list Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
这个提交包含在:
父节点
843ed69f3c
当前提交
1a0ef7d886
@ -81,15 +81,17 @@ public class LicenseInternalController {
|
||||
}
|
||||
|
||||
@GetMapping("/devices/{deviceId}")
|
||||
public ResponseEntity<ApiResponse<DeviceEntity>> getDevice(
|
||||
public ResponseEntity<ApiResponse<List<DeviceEntity>>> getDevice(
|
||||
@RequestHeader(value = "X-Internal-Token", required = false) String token,
|
||||
@PathVariable String deviceId) {
|
||||
if (!isAllowed(token)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden"));
|
||||
}
|
||||
return deviceService.findByDeviceId(deviceId)
|
||||
.map(d -> ResponseEntity.ok(ApiResponse.success(d)))
|
||||
.orElse(ResponseEntity.ok(ApiResponse.error(404, "Device not found")));
|
||||
List<DeviceEntity> devices = deviceService.findByDeviceId(deviceId);
|
||||
if (devices.isEmpty()) {
|
||||
return ResponseEntity.ok(ApiResponse.error(404, "Device not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(devices));
|
||||
}
|
||||
|
||||
private boolean isAllowed(String token) {
|
||||
|
||||
@ -4,10 +4,12 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "devices")
|
||||
@Table(name = "devices",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_app_key_device_id", columnNames = {"app_key", "device_id"}))
|
||||
public class DeviceEntity {
|
||||
|
||||
@Id
|
||||
|
||||
@ -9,7 +9,8 @@ import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface DeviceRepository extends JpaRepository<DeviceEntity, String> {
|
||||
Optional<DeviceEntity> findByDeviceId(String deviceId);
|
||||
Optional<DeviceEntity> findByAppKeyAndDeviceId(String appKey, String deviceId);
|
||||
List<DeviceEntity> findByDeviceId(String deviceId);
|
||||
List<DeviceEntity> findByAppKeyOrderByRegisteredAtDesc(String appKey);
|
||||
long countByAppKeyAndIsActiveTrue(String appKey);
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class DeviceService {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public Optional<DeviceEntity> findByDeviceId(String deviceId) {
|
||||
public List<DeviceEntity> findByDeviceId(String deviceId) {
|
||||
return deviceRepository.findByDeviceId(deviceId);
|
||||
}
|
||||
|
||||
@ -48,8 +48,8 @@ public class DeviceService {
|
||||
JsonNode userInfo) {
|
||||
validatePackageName(appKey, packageName);
|
||||
|
||||
// Check if device already registered
|
||||
Optional<DeviceEntity> existingOpt = findByDeviceId(deviceId);
|
||||
// Check if device already registered for this app
|
||||
Optional<DeviceEntity> existingOpt = deviceRepository.findByAppKeyAndDeviceId(appKey, deviceId);
|
||||
if (existingOpt.isPresent()) {
|
||||
DeviceEntity existing = existingOpt.get();
|
||||
if (!Boolean.TRUE.equals(existing.getIsActive())) {
|
||||
@ -126,7 +126,7 @@ public class DeviceService {
|
||||
return new VerifyResult(false, "Token mismatch");
|
||||
}
|
||||
|
||||
DeviceEntity device = findByDeviceId(deviceId).orElse(null);
|
||||
DeviceEntity device = deviceRepository.findByAppKeyAndDeviceId(appKey, deviceId).orElse(null);
|
||||
if (device == null || !Boolean.TRUE.equals(device.getIsActive())) {
|
||||
return new VerifyResult(false, "Device not found or deactivated");
|
||||
}
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户