docs(api): 添加联调接口文档并实现功能服务管理
- 创建了完整的 API 联调文档,包含各服务地址、ID 约定和鉴权规则 - 实现了 FeatureServiceManager 用于管理服务激活和配置功能 - 添加了安全配置确保各服务间正确的身份验证机制 - 定义了统一的响应格式和错误码处理规范 - 集成了 IM、推送和更新服务的管理接口实现
这个提交包含在:
父节点
c3968e808d
当前提交
d13c6c9bc5
@ -26,6 +26,7 @@
|
||||
|
||||
- `tenant-platform` 的“服务配置”只认租户 `app.id`
|
||||
- `tenant-platform` 的“IM 管理”必须带 `appKey`
|
||||
- `tenant-platform` 的“离线推送 / 版本管理”只需要一次开通,平台差异配置在各自的管理页里维护,不再按 Android / iOS / 鸿蒙分别申请开通
|
||||
- `im-service` 代码里沿用旧参数名 `appId`,但这是历史命名,调用方传的是 `appKey`
|
||||
|
||||
## 初始化管理员账号
|
||||
|
||||
@ -39,19 +39,21 @@ public class FeatureServiceManager {
|
||||
}
|
||||
|
||||
List<FeatureServiceEntity> normalized = new ArrayList<>();
|
||||
services.stream()
|
||||
.filter(service -> service.getServiceType() == FeatureServiceEntity.ServiceType.IM)
|
||||
.findFirst()
|
||||
.ifPresent(normalized::add);
|
||||
services.stream()
|
||||
.filter(service -> service.getServiceType() != FeatureServiceEntity.ServiceType.IM)
|
||||
.forEach(normalized::add);
|
||||
for (FeatureServiceEntity.ServiceType serviceType : List.of(
|
||||
FeatureServiceEntity.ServiceType.IM,
|
||||
FeatureServiceEntity.ServiceType.PUSH,
|
||||
FeatureServiceEntity.ServiceType.UPDATE)) {
|
||||
services.stream()
|
||||
.filter(service -> service.getServiceType() == serviceType)
|
||||
.findFirst()
|
||||
.ifPresent(normalized::add);
|
||||
}
|
||||
return normalized.isEmpty() ? services : normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit an activation request. Disabling is immediate; enabling requires ops approval.
|
||||
* IM is app-wide, so duplicate checks ignore platform.
|
||||
* IM / PUSH / UPDATE are app-wide, so duplicate checks ignore platform.
|
||||
*/
|
||||
@Transactional
|
||||
public ServiceActivationRequestEntity submitActivationRequest(
|
||||
@ -60,20 +62,13 @@ public class FeatureServiceManager {
|
||||
FeatureServiceEntity.ServiceType serviceType,
|
||||
String applyReason) {
|
||||
|
||||
if (serviceType == FeatureServiceEntity.ServiceType.IM) {
|
||||
if (isAppWideService(serviceType)) {
|
||||
requestRepository.findFirstByAppIdAndServiceTypeOrderByCreatedAtDesc(appId, serviceType)
|
||||
.ifPresent(req -> {
|
||||
if (req.getStatus() == Status.PENDING) {
|
||||
throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requestRepository.findFirstByAppIdAndPlatformAndServiceTypeOrderByCreatedAtDesc(appId, platform, serviceType)
|
||||
.ifPresent(req -> {
|
||||
if (req.getStatus() == Status.PENDING) {
|
||||
throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ServiceActivationRequestEntity req = new ServiceActivationRequestEntity();
|
||||
@ -93,7 +88,7 @@ public class FeatureServiceManager {
|
||||
@Transactional
|
||||
public FeatureServiceEntity disable(String appId, FeatureServiceEntity.Platform platform,
|
||||
FeatureServiceEntity.ServiceType serviceType) {
|
||||
if (serviceType == FeatureServiceEntity.ServiceType.IM) {
|
||||
if (isAppWideService(serviceType)) {
|
||||
List<FeatureServiceEntity> services = repository.findByAppIdAndServiceType(appId, serviceType);
|
||||
if (services.isEmpty()) {
|
||||
throw new BusinessException(404, "服务未开通");
|
||||
@ -125,17 +120,19 @@ public class FeatureServiceManager {
|
||||
req.setReviewedAt(LocalDateTime.now());
|
||||
requestRepository.save(req);
|
||||
|
||||
if (req.getServiceType() == FeatureServiceEntity.ServiceType.IM) {
|
||||
if (isAppWideService(req.getServiceType())) {
|
||||
List<FeatureServiceEntity> services = repository.findByAppIdAndServiceType(req.getAppId(), req.getServiceType());
|
||||
if (services.isEmpty()) {
|
||||
FeatureServiceEntity created = new FeatureServiceEntity();
|
||||
created.setId(UUID.randomUUID().toString());
|
||||
created.setAppId(req.getAppId());
|
||||
created.setPlatform(req.getPlatform());
|
||||
created.setServiceType(req.getServiceType());
|
||||
created.setEnabled(true);
|
||||
created.setCreatedAt(LocalDateTime.now());
|
||||
repository.save(created);
|
||||
for (FeatureServiceEntity.Platform platform : FeatureServiceEntity.Platform.values()) {
|
||||
FeatureServiceEntity created = new FeatureServiceEntity();
|
||||
created.setId(UUID.randomUUID().toString());
|
||||
created.setAppId(req.getAppId());
|
||||
created.setPlatform(platform);
|
||||
created.setServiceType(req.getServiceType());
|
||||
created.setEnabled(true);
|
||||
created.setCreatedAt(LocalDateTime.now());
|
||||
repository.save(created);
|
||||
}
|
||||
} else {
|
||||
services.forEach(service -> service.setEnabled(true));
|
||||
repository.saveAll(services);
|
||||
@ -366,6 +363,12 @@ public class FeatureServiceManager {
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isAppWideService(FeatureServiceEntity.ServiceType serviceType) {
|
||||
return serviceType == FeatureServiceEntity.ServiceType.IM
|
||||
|| serviceType == FeatureServiceEntity.ServiceType.PUSH
|
||||
|| serviceType == FeatureServiceEntity.ServiceType.UPDATE;
|
||||
}
|
||||
|
||||
private JsonNode readConfigNode(String appId,
|
||||
FeatureServiceEntity.Platform platform,
|
||||
FeatureServiceEntity.ServiceType serviceType) {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.xuqm.update.config;
|
||||
|
||||
import com.xuqm.common.security.JwtAuthFilter;
|
||||
import com.xuqm.common.security.JwtUtil;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
@ -8,6 +10,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
@ -18,6 +21,12 @@ import java.util.List;
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
public SecurityConfig(JwtUtil jwtUtil) {
|
||||
this.jwtUtil = jwtUtil;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
@ -35,6 +44,7 @@ public class SecurityConfig {
|
||||
).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
|
||||
.httpBasic(AbstractHttpConfigurer::disable)
|
||||
.formLogin(AbstractHttpConfigurer::disable);
|
||||
return http.build();
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户