支持彻底关闭文档页面 + 修复云端录像偶现callId错误问题

pull/1489/head
648540858 2024-05-23 17:10:45 +08:00
parent d70bfb53dd
commit 2daa59d78c
13 changed files with 76 additions and 33 deletions

View File

@ -7,6 +7,7 @@ import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springdoc.core.GroupedOpenApi; import org.springdoc.core.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -18,6 +19,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration @Configuration
@Order(1) @Order(1)
@ConditionalOnProperty(value = "user-settings.doc-enable", havingValue = "true", matchIfMissing = true)
public class SpringDocConfig { public class SpringDocConfig {
@Value("${doc.enabled: true}") @Value("${doc.enabled: true}")

View File

@ -54,6 +54,8 @@ public class UserSetting {
private Boolean deviceStatusNotify = Boolean.TRUE; private Boolean deviceStatusNotify = Boolean.TRUE;
private Boolean useCustomSsrcForParentInvite = Boolean.TRUE; private Boolean useCustomSsrcForParentInvite = Boolean.TRUE;
private Boolean docEnable = Boolean.TRUE;
private String serverId = "000000"; private String serverId = "000000";
private String thirdPartyGBIdReg = "[\\s\\S]*"; private String thirdPartyGBIdReg = "[\\s\\S]*";
@ -315,4 +317,12 @@ public class UserSetting {
public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) { public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) {
this.registerKeepIntDialog = registerKeepIntDialog; this.registerKeepIntDialog = registerKeepIntDialog;
} }
public Boolean getDocEnable() {
return docEnable;
}
public void setDocEnable(Boolean docEnable) {
this.docEnable = docEnable;
}
} }

View File

@ -35,10 +35,16 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// 忽略登录请求的token验证 // 忽略登录请求的token验证
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
System.out.println(requestURI);
if ((requestURI.startsWith("/doc.html") || requestURI.startsWith("/swagger-ui") ) && !userSetting.getDocEnable()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (requestURI.equalsIgnoreCase("/api/user/login")) { if (requestURI.equalsIgnoreCase("/api/user/login")) {
chain.doFilter(request, response); chain.doFilter(request, response);
return; return;
} }
if (!userSetting.isInterfaceAuthentication()) { if (!userSetting.isInterfaceAuthentication()) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() ); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
SecurityContextHolder.getContext().setAuthentication(token); SecurityContextHolder.getContext().setAuthentication(token);

View File

@ -117,7 +117,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.authorizeRequests() .authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
.antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll() .antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html#/**").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
// 异常处理器 // 异常处理器
.and() .and()

View File

@ -29,6 +29,7 @@ import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.MediaServerUtils;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
@ -47,7 +48,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.sip.InvalidArgumentException; import javax.sip.InvalidArgumentException;
import javax.sip.SipException; import javax.sip.SipException;
import java.text.ParseException; import java.text.ParseException;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -179,7 +179,7 @@ public class ZLMHttpHookListener {
} }
}); });
if (!"rtp".equals(param.getApp())) { if (!"rtp".equals(param.getApp())) {
Map<String, String> paramMap = urlParamToMap(param.getParams()); Map<String, String> paramMap = MediaServerUtils.urlParamToMap(param.getParams());
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) {
return new HookResult(401, "Unauthorized"); return new HookResult(401, "Unauthorized");
@ -220,7 +220,7 @@ public class ZLMHttpHookListener {
logger.info("推流鉴权失败: 缺少必要参数sign=md5(user表的pushKey)"); logger.info("推流鉴权失败: 缺少必要参数sign=md5(user表的pushKey)");
return new HookResultForOnPublish(401, "Unauthorized"); return new HookResultForOnPublish(401, "Unauthorized");
} }
Map<String, String> paramMap = urlParamToMap(param.getParams()); Map<String, String> paramMap = MediaServerUtils.urlParamToMap(param.getParams());
String sign = paramMap.get("sign"); String sign = paramMap.get("sign");
if (sign == null) { if (sign == null) {
logger.info("推流鉴权失败: 缺少必要参数sign=md5(user表的pushKey)"); logger.info("推流鉴权失败: 缺少必要参数sign=md5(user表的pushKey)");
@ -899,22 +899,4 @@ public class ZLMHttpHookListener {
return HookResult.SUCCESS(); return HookResult.SUCCESS();
} }
private Map<String, String> urlParamToMap(String params) {
HashMap<String, String> map = new HashMap<>();
if (ObjectUtils.isEmpty(params)) {
return map;
}
String[] paramsArray = params.split("&");
if (paramsArray.length == 0) {
return map;
}
for (String param : paramsArray) {
String[] paramArray = param.split("=");
if (paramArray.length == 2) {
map.put(paramArray[0], paramArray[1]);
}
}
return map;
}
} }

View File

@ -15,6 +15,7 @@ public class OnRecordMp4HookParam extends HookParam{
private String vhost; private String vhost;
private long start_time; private long start_time;
private double time_len; private double time_len;
private String params;
public String getApp() { public String getApp() {
return app; return app;
@ -96,6 +97,14 @@ public class OnRecordMp4HookParam extends HookParam{
this.time_len = time_len; this.time_len = time_len;
} }
public String getParams() {
return params;
}
public void setParams(String params) {
this.params = params;
}
@Override @Override
public String toString() { public String toString() {
return "OnRecordMp4HookParam{" + return "OnRecordMp4HookParam{" +
@ -109,6 +118,7 @@ public class OnRecordMp4HookParam extends HookParam{
", vhost='" + vhost + '\'' + ", vhost='" + vhost + '\'' +
", start_time=" + start_time + ", start_time=" + start_time +
", time_len=" + time_len + ", time_len=" + time_len +
", params=" + params +
'}'; '}';
} }
} }

View File

@ -1,6 +1,9 @@
package com.genersoft.iot.vmp.service.bean; package com.genersoft.iot.vmp.service.bean;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
import com.genersoft.iot.vmp.utils.MediaServerUtils;
import java.util.Map;
/** /**
* *
@ -88,6 +91,10 @@ public class CloudRecordItem {
cloudRecordItem.setMediaServerId(param.getMediaServerId()); cloudRecordItem.setMediaServerId(param.getMediaServerId());
cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000); cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000);
cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000); cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000);
Map<String, String> paramsMap = MediaServerUtils.urlParamToMap(param.getParams());
if (paramsMap.get("callId") != null) {
cloudRecordItem.setCallId(paramsMap.get("callId"));
}
return cloudRecordItem; return cloudRecordItem;
} }

View File

@ -7,7 +7,6 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
import com.genersoft.iot.vmp.service.ICloudRecordService; import com.genersoft.iot.vmp.service.ICloudRecordService;
import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaServerService;
@ -26,8 +25,12 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.*; import java.time.LocalDate;
import java.util.*; import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Service @Service
@DS("share") @DS("share")
@ -102,11 +105,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
@Override @Override
public void addRecord(OnRecordMp4HookParam param) { public void addRecord(OnRecordMp4HookParam param) {
CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param);
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); logger.info("[添加录像记录] {}/{}, callId: {}, 文件大小:{}, 时长: {}秒", param.getApp(), param.getStream(),cloudRecordItem.getCallId(), param.getFile_size(),param.getTime_len());
if (streamAuthorityInfo != null) {
cloudRecordItem.setCallId(streamAuthorityInfo.getCallId());
}
logger.info("[添加录像记录] {}/{} 文件大小:{}, 时长: {}秒", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len());
cloudRecordServiceMapper.add(cloudRecordItem); cloudRecordServiceMapper.add(cloudRecordItem);
} }

View File

@ -0,0 +1,26 @@
package com.genersoft.iot.vmp.utils;
import org.springframework.util.ObjectUtils;
import java.util.HashMap;
import java.util.Map;
public class MediaServerUtils {
public static Map<String, String> urlParamToMap(String params) {
HashMap<String, String> map = new HashMap<>();
if (ObjectUtils.isEmpty(params)) {
return map;
}
String[] paramsArray = params.split("&");
if (paramsArray.length == 0) {
return map;
}
for (String param : paramsArray) {
String[] paramArray = param.split("=");
if (paramArray.length == 2) {
map.put(paramArray[0], paramArray[1]);
}
}
return map;
}
}

View File

@ -241,6 +241,8 @@ user-settings:
register-again-after-time: 60 register-again-after-time: 60
# 国标续订方式true为续订每次注册在同一个会话里false为重新注册每次使用新的会话 # 国标续订方式true为续订每次注册在同一个会话里false为重新注册每次使用新的会话
register-keep-int-dialog: false register-keep-int-dialog: false
# 开启接口文档页面。 默认开启生产环境建议关闭遇到swagger相关的漏洞时也可以关闭
doc-enable: true
# 跨域配置,不配置此项则允许所有跨域请求,配置后则只允许配置的页面的地址请求, 可以配置多个 # 跨域配置,不配置此项则允许所有跨域请求,配置后则只允许配置的页面的地址请求, 可以配置多个
allowed-origins: allowed-origins:
- http://localhost:8008 - http://localhost:8008

View File

@ -110,7 +110,4 @@ user-settings:
auto-apply-play: true auto-apply-play: true
# 设备/通道状态变化时发送消息 # 设备/通道状态变化时发送消息
device-status-notify: true device-status-notify: true
# [可选] 日志配置, 一般不需要改
logging:
config: classpath:logback-spring.xml

View File

@ -166,6 +166,7 @@ create table wvp_media_server (
hook_alive_interval integer, hook_alive_interval integer,
record_path character varying(255), record_path character varying(255),
record_day integer default 7, record_day integer default 7,
transcode_suffix character varying(255),
constraint uk_media_server_unique_ip_http_port unique (ip, http_port) constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
); );

View File

@ -166,6 +166,7 @@ create table wvp_media_server (
hook_alive_interval integer, hook_alive_interval integer,
record_path character varying(255), record_path character varying(255),
record_day integer default 7, record_day integer default 7,
transcode_suffix character varying(255),
constraint uk_media_server_unique_ip_http_port unique (ip, http_port) constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
); );