feat(license): 添加应用信息接口并增强验证逻辑

- 在 SecurityConfig 中为 /api/license/app-info 接口添加无需认证访问权限
- 优化 GlobalExceptionHandler 中的参数验证错误信息显示,提供详细的字段错误信息
- 移除 RegisterRequest 和 VerifyRequest 中的注解验证,改用代码手动验证
- 为 register 接口添加 deviceId 非空检查
- 为 verify 接口添加 deviceId 和 token 非空检查
- 移除 RegisterRequest 中对 deviceId 的 @NotBlank 注解验证
- 移除 VerifyRequest 中对 deviceId 和 token 的 @NotBlank 注解验证
这个提交包含在:
XuqmGroup 2026-05-23 02:23:53 +08:00
父节点 b7c2f0144f
当前提交 8e131906d8
共有 3 个文件被更改,包括 20 次插入9 次删除

查看文件

@ -36,7 +36,7 @@ public class SecurityConfig {
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/api/license/register", "/api/license/verify").permitAll() .requestMatchers("/api/license/register", "/api/license/verify", "/api/license/app-info").permitAll()
.requestMatchers("/api/license/internal/**", "/actuator/health", "/actuator/info").permitAll() .requestMatchers("/api/license/internal/**", "/actuator/health", "/actuator/info").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )

查看文件

@ -17,6 +17,10 @@ public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Void>> handleValidationException(MethodArgumentNotValidException e) { public ResponseEntity<ApiResponse<Void>> handleValidationException(MethodArgumentNotValidException e) {
return ResponseEntity.badRequest().body(ApiResponse.badRequest("Invalid request")); String detail = e.getBindingResult().getFieldErrors().stream()
.map(f -> f.getField() + ": " + f.getDefaultMessage())
.reduce((a, b) -> a + "; " + b)
.orElse("Invalid request");
return ResponseEntity.badRequest().body(ApiResponse.badRequest(detail));
} }
} }

查看文件

@ -9,8 +9,6 @@ import com.xuqm.common.security.LicenseFileCrypto;
import com.xuqm.license.entity.AppLicenseEntity; import com.xuqm.license.entity.AppLicenseEntity;
import com.xuqm.license.service.AppLicenseService; import com.xuqm.license.service.AppLicenseService;
import com.xuqm.license.service.DeviceService; import com.xuqm.license.service.DeviceService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -30,7 +28,10 @@ public class LicensePublicController {
} }
@PostMapping("/register") @PostMapping("/register")
public ResponseEntity<ApiResponse<Map<String, Object>>> register(@Valid @RequestBody RegisterRequest req) { public ResponseEntity<ApiResponse<Map<String, Object>>> register(@RequestBody RegisterRequest req) {
if (req.deviceId() == null || req.deviceId().isBlank()) {
throw new BusinessException(400, "deviceId 不能为空");
}
String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile()); String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile());
DeviceService.RegisterResult result = deviceService.register( DeviceService.RegisterResult result = deviceService.register(
resolvedAppKey, resolvedAppKey,
@ -50,7 +51,13 @@ public class LicensePublicController {
} }
@PostMapping("/verify") @PostMapping("/verify")
public ResponseEntity<ApiResponse<Map<String, Object>>> verify(@Valid @RequestBody VerifyRequest req) { public ResponseEntity<ApiResponse<Map<String, Object>>> verify(@RequestBody VerifyRequest req) {
if (req.deviceId() == null || req.deviceId().isBlank()) {
throw new BusinessException(400, "deviceId 不能为空");
}
if (req.token() == null || req.token().isBlank()) {
throw new BusinessException(400, "token 不能为空");
}
String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile()); String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile());
DeviceService.VerifyResult result = deviceService.verify(resolvedAppKey, req.deviceId(), req.token(), req.userInfo()); DeviceService.VerifyResult result = deviceService.verify(resolvedAppKey, req.deviceId(), req.token(), req.userInfo());
Map<String, Object> data = new LinkedHashMap<>(); Map<String, Object> data = new LinkedHashMap<>();
@ -95,7 +102,7 @@ public class LicensePublicController {
String appKey, String appKey,
@JsonProperty("packageName") @JsonAlias("package_name") String packageName, @JsonProperty("packageName") @JsonAlias("package_name") String packageName,
@JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile, @JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile,
@NotBlank @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId, @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId,
@JsonProperty("deviceName") @JsonAlias("device_name") String deviceName, @JsonProperty("deviceName") @JsonAlias("device_name") String deviceName,
@JsonProperty("deviceModel") @JsonAlias("device_model") String deviceModel, @JsonProperty("deviceModel") @JsonAlias("device_model") String deviceModel,
@JsonProperty("deviceVendor") @JsonAlias("device_vendor") String deviceVendor, @JsonProperty("deviceVendor") @JsonAlias("device_vendor") String deviceVendor,
@ -107,8 +114,8 @@ public class LicensePublicController {
String appKey, String appKey,
@JsonProperty("packageName") @JsonAlias("package_name") String packageName, @JsonProperty("packageName") @JsonAlias("package_name") String packageName,
@JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile, @JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile,
@NotBlank @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId, @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId,
@NotBlank String token, String token,
@JsonProperty("userInfo") @JsonAlias("user_info") JsonNode userInfo @JsonProperty("userInfo") @JsonAlias("user_info") JsonNode userInfo
) {} ) {}
} }