feat: 添加设备自注册接口并优化设备在线管理逻辑
- 新增 `AndroidDeviceController` 用于设备自注册 - 优化 `DeviceOnlineManagementServiceImpl` 和 `AndroidDeviceBindingServiceImpl` 中的设备在线管理逻辑 - 更新 `DeviceInfoMapper` 添加 `updateBaseInfoByIdIgnoreTenant` 方法 - 在 `AndroidPublicMeetingController` 中添加设备未注册时的异常处理 - 更新 `AndroidAuthService` 和 `AndroidAuthServiceImpl` 支持设备是否需要注册的验证dev_na
parent
8716608afa
commit
e7659b1e31
|
|
@ -1,6 +1,7 @@
|
|||
package com.imeeting.controller.android;
|
||||
|
||||
import com.imeeting.service.android.AndroidDeviceBindingService;
|
||||
import com.imeeting.service.android.AndroidDeviceRegistrationService;
|
||||
import com.imeeting.support.AndroidRequestLogHelper;
|
||||
import com.unisbase.auth.JwtTokenProvider;
|
||||
import com.unisbase.common.ApiResponse;
|
||||
|
|
@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
public class AndroidAuthController {
|
||||
private final AuthService authService;
|
||||
private final AndroidDeviceBindingService androidDeviceBindingService;
|
||||
private final AndroidDeviceRegistrationService androidDeviceRegistrationService;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
@Operation(summary = "Android登录")
|
||||
|
|
@ -52,6 +54,10 @@ public class AndroidAuthController {
|
|||
"deviceId", deviceId,
|
||||
"appVersion", appVersion,
|
||||
"platform", platform);
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
throw new IllegalArgumentException("X-Android-Device-Id不能为空");
|
||||
}
|
||||
androidDeviceRegistrationService.requireRegistered(deviceId.trim());
|
||||
TokenResponse response = authService.login(request, true);
|
||||
if (response != null && response.getUser() != null && response.getCurrentTenantId() != null && StringUtils.hasText(deviceId)) {
|
||||
androidDeviceBindingService.bindPrivateDevice(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.imeeting.controller.android;
|
||||
|
||||
import com.imeeting.dto.android.AndroidAuthContext;
|
||||
import com.imeeting.dto.android.AndroidDeviceRegisterRequest;
|
||||
import com.imeeting.dto.android.AndroidDeviceRegisterResponse;
|
||||
import com.imeeting.service.android.AndroidAuthService;
|
||||
import com.imeeting.service.android.AndroidDeviceRegistrationService;
|
||||
import com.imeeting.support.AndroidRequestLogHelper;
|
||||
import com.unisbase.common.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "Android设备接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/android/devices")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AndroidDeviceController {
|
||||
private final AndroidAuthService androidAuthService;
|
||||
private final AndroidDeviceRegistrationService androidDeviceRegistrationService;
|
||||
|
||||
@Operation(summary = "设备自注册")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "返回设备注册后的基础信息",
|
||||
content = @Content(schema = @Schema(implementation = AndroidDeviceRegisterResponse.class))
|
||||
)
|
||||
})
|
||||
@PostMapping("/register")
|
||||
public ApiResponse<AndroidDeviceRegisterResponse> register(HttpServletRequest request,
|
||||
@RequestBody(required = false) AndroidDeviceRegisterRequest command) {
|
||||
AndroidRequestLogHelper.logRequest(log, "Android设备", "设备自注册", "request", command);
|
||||
AndroidAuthContext authContext = androidAuthService.authenticateHttp(request, false);
|
||||
AndroidDeviceRegisterResponse response = androidDeviceRegistrationService.register(
|
||||
authContext.getDeviceId(),
|
||||
command == null ? null : command.getDeviceName(),
|
||||
command == null ? authContext.getPlatform() : command.getTerminalType(),
|
||||
command == null ? authContext.getAppVersion() : command.getTerminalVersion()
|
||||
);
|
||||
return ApiResponse.ok(response);
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,9 @@ public class AndroidPublicMeetingController {
|
|||
throw new RuntimeException("设备ID不能为空");
|
||||
}
|
||||
var device = deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceId);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("设备未注册,请先完成设备注册");
|
||||
}
|
||||
if (device != null && device.getUserId() != null) {
|
||||
throw new RuntimeException("当前设备为私有设备,请走私有设备发会流程");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,20 @@ public interface DeviceInfoMapper extends BaseMapper<DeviceInfoEntity> {
|
|||
""")
|
||||
int updateConnectionInfoByIdIgnoreTenant(DeviceInfoEntity deviceInfoEntity);
|
||||
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
@Update("""
|
||||
<script>
|
||||
UPDATE biz_device_info
|
||||
SET device_name = #{deviceName},
|
||||
terminal_type = #{terminalType},
|
||||
terminal_version = #{terminalVersion},
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE device_id = #{deviceId}
|
||||
AND is_deleted = 0
|
||||
</script>
|
||||
""")
|
||||
int updateBaseInfoByIdIgnoreTenant(DeviceInfoEntity deviceInfoEntity);
|
||||
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
@Update("""
|
||||
UPDATE biz_device_info
|
||||
|
|
|
|||
|
|
@ -7,4 +7,6 @@ public interface AndroidAuthService {
|
|||
AndroidAuthContext authenticateGrpc(String deviceId, String appVersion, String platform);
|
||||
|
||||
AndroidAuthContext authenticateHttp(HttpServletRequest request);
|
||||
|
||||
AndroidAuthContext authenticateHttp(HttpServletRequest request, boolean requireRegistered);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,18 +40,21 @@ public class AndroidAuthServiceImpl implements AndroidAuthService {
|
|||
if (properties.isEnabled() && !properties.isAllowAnonymous()) {
|
||||
throw new RuntimeException("Android gRPC push does not allow anonymous access");
|
||||
}
|
||||
assertDeviceEnabled(deviceId);
|
||||
DeviceInfoEntity device = requireRegisteredDevice(deviceId);
|
||||
assertDeviceEnabled(device);
|
||||
AndroidAuthContext context = buildContext("NONE", true, deviceId, null, appVersion, platform, null, null, null, null);
|
||||
DeviceInfoEntity device = deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceId.trim());
|
||||
if (device != null) {
|
||||
context.setUserId(device.getUserId());
|
||||
context.setTenantId(device.getTenantId());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidAuthContext authenticateHttp(HttpServletRequest request) {
|
||||
return authenticateHttp(request, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidAuthContext authenticateHttp(HttpServletRequest request, boolean requireRegistered) {
|
||||
LoginUser loginUser = currentLoginUser();
|
||||
String resolvedToken = resolveHttpToken(request);
|
||||
String deviceId = firstHeader(request, HEADER_DEVICE_ID);
|
||||
|
|
@ -61,7 +64,8 @@ public class AndroidAuthServiceImpl implements AndroidAuthService {
|
|||
|
||||
requireAndroidHttpHeaders(deviceId, appVersion, platform);
|
||||
log.info("[安卓接口访问]X-Android-Device-Id={},X-Android-App-Version={},X-Android-Platform={}",deviceId,appVersion,platform);
|
||||
assertDeviceEnabled(deviceId);
|
||||
DeviceInfoEntity device = requireRegistered ? requireRegisteredDevice(deviceId) : findDevice(deviceId);
|
||||
assertDeviceEnabled(device);
|
||||
if (loginUser != null) {
|
||||
androidDeviceBindingService.validatePrivateDeviceAccess(deviceId, loginUser.getTenantId(), loginUser.getUserId());
|
||||
return buildContext("USER_JWT", false,
|
||||
|
|
@ -192,16 +196,27 @@ public class AndroidAuthServiceImpl implements AndroidAuthService {
|
|||
}
|
||||
}
|
||||
|
||||
private void assertDeviceEnabled(String deviceId) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
return;
|
||||
}
|
||||
DeviceInfoEntity device = deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceId.trim());
|
||||
private void assertDeviceEnabled(DeviceInfoEntity device) {
|
||||
if (device != null && device.getStatus() != null && device.getStatus() == 0) {
|
||||
throw new BusinessException("403", "设备被禁用");
|
||||
}
|
||||
}
|
||||
|
||||
private DeviceInfoEntity requireRegisteredDevice(String deviceId) {
|
||||
DeviceInfoEntity device = findDevice(deviceId);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("设备未注册,请先调用设备注册接口");
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
private DeviceInfoEntity findDevice(String deviceId) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
return null;
|
||||
}
|
||||
return deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceId.trim());
|
||||
}
|
||||
|
||||
private String normalizeToken(String token) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -21,19 +21,10 @@ public class AndroidDeviceBindingServiceImpl implements AndroidDeviceBindingServ
|
|||
throw new RuntimeException("设备登录缺少绑定上下文");
|
||||
}
|
||||
DeviceInfoEntity existing = deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceCode.trim());
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
if (existing == null) {
|
||||
DeviceInfoEntity created = new DeviceInfoEntity();
|
||||
created.setTenantId(tenantId);
|
||||
created.setUserId(userId);
|
||||
created.setDeviceCode(deviceCode.trim());
|
||||
created.setTerminalType(normalize(platform));
|
||||
created.setTerminalVersion(normalize(appVersion));
|
||||
created.setLastOnlineAt(now);
|
||||
created.setStatus(1);
|
||||
deviceInfoMapper.insert(created);
|
||||
return;
|
||||
throw new RuntimeException("设备未注册,请先完成设备注册");
|
||||
}
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
existing.setTenantId(tenantId);
|
||||
existing.setUserId(userId);
|
||||
existing.setTerminalType(normalize(platform));
|
||||
|
|
|
|||
|
|
@ -34,21 +34,10 @@ public class DeviceOnlineManagementServiceImpl implements DeviceOnlineManagement
|
|||
}
|
||||
String deviceCode = authContext.getDeviceId().trim();
|
||||
DeviceInfoEntity existing = deviceInfoMapper.selectByDeviceCodeIgnoreTenant(deviceCode);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
if (existing == null) {
|
||||
DeviceInfoEntity created = new DeviceInfoEntity();
|
||||
created.setTenantId(authContext.getTenantId());
|
||||
created.setUserId(authContext.getUserId());
|
||||
created.setDeviceCode(deviceCode);
|
||||
created.setDeviceName(null);
|
||||
created.setTerminalType(normalizeTerminalType(authContext.getPlatform()));
|
||||
created.setTerminalVersion(normalize(authContext.getAppVersion()));
|
||||
created.setLastOnlineAt(now);
|
||||
created.setStatus(1);
|
||||
deviceInfoMapper.insert(created);
|
||||
return;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
existing.setTerminalType(normalizeTerminalType(authContext.getPlatform()));
|
||||
existing.setTerminalVersion(normalize(authContext.getAppVersion()));
|
||||
existing.setLastOnlineAt(now);
|
||||
|
|
|
|||
Loading…
Reference in New Issue