Commit b5c9de775db8078e37f276640854d5850b3b1335

Authored by 648540858
1 parent bfd1628d

补充漏掉的文件

src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -27,6 +27,7 @@ package com.genersoft.iot.vmp.gb28181.auth; @@ -27,6 +27,7 @@ package com.genersoft.iot.vmp.gb28181.auth;
27 27
28 import java.security.MessageDigest; 28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException; 29 import java.security.NoSuchAlgorithmException;
  30 +import java.text.DecimalFormat;
30 import java.util.Date; 31 import java.util.Date;
31 import java.util.Random; 32 import java.util.Random;
32 33
@@ -103,9 +104,12 @@ public class DigestServerAuthenticationHelper { @@ -103,9 +104,12 @@ public class DigestServerAuthenticationHelper {
103 .createWWWAuthenticateHeader(DEFAULT_SCHEME); 104 .createWWWAuthenticateHeader(DEFAULT_SCHEME);
104 proxyAuthenticate.setParameter("realm", realm); 105 proxyAuthenticate.setParameter("realm", realm);
105 proxyAuthenticate.setParameter("nonce", generateNonce()); 106 proxyAuthenticate.setParameter("nonce", generateNonce());
106 - proxyAuthenticate.setParameter("opaque", "");  
107 - proxyAuthenticate.setParameter("stale", "FALSE");  
108 - proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM); 107 +
  108 +// proxyAuthenticate.setParameter("opaque", "");
  109 +// proxyAuthenticate.setParameter("stale", "FALSE");
  110 +// proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
  111 +
  112 + proxyAuthenticate.setParameter("qop", "auth");
109 response.setHeader(proxyAuthenticate); 113 response.setHeader(proxyAuthenticate);
110 } catch (Exception ex) { 114 } catch (Exception ex) {
111 InternalErrorHandler.handleException(ex); 115 InternalErrorHandler.handleException(ex);
@@ -170,42 +174,116 @@ public class DigestServerAuthenticationHelper { @@ -170,42 +174,116 @@ public class DigestServerAuthenticationHelper {
170 public boolean doAuthenticatePlainTextPassword(Request request, String pass) { 174 public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
171 AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); 175 AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
172 if ( authHeader == null ) return false; 176 if ( authHeader == null ) return false;
173 - String realm = authHeader.getRealm();  
174 - String username = authHeader.getUsername();  
175 -  
176 - 177 + String realm = authHeader.getRealm().trim();
  178 + String username = authHeader.getUsername().trim();
  179 +
177 if ( username == null || realm == null ) { 180 if ( username == null || realm == null ) {
178 return false; 181 return false;
179 } 182 }
180 -  
181 183
182 String nonce = authHeader.getNonce(); 184 String nonce = authHeader.getNonce();
183 URI uri = authHeader.getURI(); 185 URI uri = authHeader.getURI();
184 if (uri == null) { 186 if (uri == null) {
185 return false; 187 return false;
186 } 188 }
187 - 189 + // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
  190 + String qop = authHeader.getQop().trim();
  191 +
  192 + // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
  193 + // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
  194 + String cNonce = authHeader.getCNonce().trim();
  195 +
  196 + // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量
  197 + int nc = authHeader.getNonceCount();
  198 + String ncStr = new DecimalFormat("00000000").format(nc);
  199 +// String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
188 200
189 String A1 = username + ":" + realm + ":" + pass; 201 String A1 = username + ":" + realm + ":" + pass;
190 String A2 = request.getMethod().toUpperCase() + ":" + uri.toString(); 202 String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
191 byte mdbytes[] = messageDigest.digest(A1.getBytes()); 203 byte mdbytes[] = messageDigest.digest(A1.getBytes());
192 String HA1 = toHexString(mdbytes); 204 String HA1 = toHexString(mdbytes);
  205 + System.out.println("A1: " + A1);
  206 + System.out.println("A2: " + A2);
193 207
194 -  
195 mdbytes = messageDigest.digest(A2.getBytes()); 208 mdbytes = messageDigest.digest(A2.getBytes());
196 String HA2 = toHexString(mdbytes); 209 String HA2 = toHexString(mdbytes);
197 - 210 + System.out.println("HA1: " + HA1);
  211 + System.out.println("HA2: " + HA2);
198 String cnonce = authHeader.getCNonce(); 212 String cnonce = authHeader.getCNonce();
  213 + System.out.println("nonce: " + nonce);
  214 + System.out.println("nc: " + ncStr);
  215 + System.out.println("cnonce: " + cnonce);
  216 + System.out.println("qop: " + qop);
199 String KD = HA1 + ":" + nonce; 217 String KD = HA1 + ":" + nonce;
200 - if (cnonce != null) {  
201 - KD += ":" + cnonce; 218 +
  219 + if (qop != null && qop.equals("auth") ) {
  220 + if (nc != -1) {
  221 + KD += ":" + ncStr;
  222 + }
  223 + if (cnonce != null) {
  224 + KD += ":" + cnonce;
  225 + }
  226 + KD += ":" + qop;
202 } 227 }
203 KD += ":" + HA2; 228 KD += ":" + HA2;
  229 + System.out.println("KD: " + KD);
204 mdbytes = messageDigest.digest(KD.getBytes()); 230 mdbytes = messageDigest.digest(KD.getBytes());
205 String mdString = toHexString(mdbytes); 231 String mdString = toHexString(mdbytes);
  232 + System.out.println("mdString: " + mdString);
206 String response = authHeader.getResponse(); 233 String response = authHeader.getResponse();
  234 + System.out.println("response: " + response);
207 return mdString.equals(response); 235 return mdString.equals(response);
208 236
209 } 237 }
210 238
  239 +
  240 + public static void main(String[] args) throws NoSuchAlgorithmException {
  241 + MessageDigest messageDigest2 = MessageDigest.getInstance(DEFAULT_ALGORITHM);
  242 + String realm = "DS-2CD2520F";
  243 + String username = "admin";
  244 + String passwd = "12345";
  245 +
  246 + String nonce = "4d6a553452444d30525441364e6d4d304e6a68684e47553d";
  247 +
  248 + String uri = "/ISAPI/Streaming/channels/101/picture";
  249 + // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
  250 + String qop = "auth";
  251 +
  252 + // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
  253 + // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
  254 + String cNonce = "C1A5298F939E87E8F962A5EDFC206918";
  255 +
  256 + // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量
  257 + int nc = 1;
  258 +
  259 + String A1 = username + ":" + realm + ":" + passwd;
  260 + System.out.println("A1: " + A1);
  261 + String A2 = "GET" + ":" + uri.toString();
  262 + System.out.println("A2: " + A2);
  263 + byte mdbytes[] = messageDigest2.digest(A1.getBytes());
  264 + String HA1 = toHexString(mdbytes);
  265 + System.out.println("HA1: " + HA1);
  266 +
  267 + mdbytes = messageDigest2.digest(A2.getBytes());
  268 + String HA2 = toHexString(mdbytes);
  269 + System.out.println("HA2: " + HA2);
  270 + String cnonce = "93d4d37df32e1a85";
  271 + String KD = HA1 + ":" + nonce;
  272 +
  273 + if (nc != -1) {
  274 + KD += ":" + "00000001";
  275 + }
  276 + if (cnonce != null) {
  277 + KD += ":" + cnonce;
  278 + }
  279 + if (qop != null) {
  280 + KD += ":" + qop;
  281 + }
  282 + KD += ":" + HA2;
  283 + System.out.println("KD: " + KD);
  284 + mdbytes = messageDigest2.digest(KD.getBytes());
  285 + String mdString = toHexString(mdbytes);
  286 + String response = "3993a815e5cdaf4470e9b4f9bd41cf4a";
  287 + System.out.println(mdString);
  288 + }
211 } 289 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.beans.factory.annotation.Value;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +import java.util.HashMap;
  11 +import java.util.Map;
  12 +
  13 +@Component
  14 +public class ZLMRTPServerFactory {
  15 +
  16 + private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
  17 +
  18 + @Value("${media.rtp.udpPortRange}")
  19 + private String udpPortRange;
  20 +
  21 + @Autowired
  22 + private ZLMRESTfulUtils zlmresTfulUtils;
  23 +
  24 + private int[] udpPortRangeArray = new int[2];
  25 +
  26 + private int currentPort = 0;
  27 +
  28 + public int createRTPServer(String streamId) {
  29 + Map<String, Object> param = new HashMap<>();
  30 + int result = -1;
  31 + int newPort = getPortFromUdpPortRange();
  32 + param.put("port", newPort);
  33 + param.put("enable_tcp", 1);
  34 + param.put("stream_id", streamId);
  35 + JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
  36 + System.out.println(jsonObject);
  37 +
  38 + if (jsonObject != null) {
  39 + switch (jsonObject.getInteger("code")){
  40 + case 0:
  41 + result= newPort;
  42 + break;
  43 + case -300: // id已经存在
  44 + result = newPort;
  45 + break;
  46 + case -400: // 端口占用
  47 + result= createRTPServer(streamId);
  48 + break;
  49 + default:
  50 + logger.error("创建RTP Server 失败: " + jsonObject.getString("msg"));
  51 + break;
  52 + }
  53 + }else {
  54 + // 检查ZLM状态
  55 + logger.error("创建RTP Server 失败: 请检查ZLM服务");
  56 + }
  57 + return result;
  58 + }
  59 +
  60 + public boolean closeRTPServer(String streamId) {
  61 + boolean result = false;
  62 + Map<String, Object> param = new HashMap<>();
  63 + param.put("stream_id", streamId);
  64 + JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
  65 + if (jsonObject != null ) {
  66 + if (jsonObject.getInteger("code") == 0) {
  67 + result = jsonObject.getInteger("hit") == 1;
  68 + }else {
  69 + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  70 + }
  71 + }else {
  72 + // 检查ZLM状态
  73 + logger.error("关闭RTP Server 失败: 请检查ZLM服务");
  74 + }
  75 + return result;
  76 + }
  77 +
  78 + private int getPortFromUdpPortRange() {
  79 + if (currentPort == 0) {
  80 + String[] udpPortRangeStrArray = udpPortRange.split(",");
  81 + udpPortRangeArray[0] = Integer.parseInt(udpPortRangeStrArray[0]);
  82 + udpPortRangeArray[1] = Integer.parseInt(udpPortRangeStrArray[1]);
  83 + }
  84 +
  85 + if (currentPort == 0 || currentPort++ > udpPortRangeArray[1]) {
  86 + currentPort = udpPortRangeArray[0];
  87 + return udpPortRangeArray[0];
  88 + } else {
  89 + if (currentPort % 2 == 1) {
  90 + currentPort++;
  91 + }
  92 + return currentPort++;
  93 + }
  94 + }
  95 +}
src/main/resources/application.yml
1 spring: 1 spring:
2 profiles: 2 profiles:
3 - active: dev  
4 \ No newline at end of file 3 \ No newline at end of file
  4 + active: local
5 \ No newline at end of file 5 \ No newline at end of file
web_src/src/components/UiHeader.vue
@@ -23,4 +23,4 @@ export default { @@ -23,4 +23,4 @@ export default {
23 } 23 }
24 } 24 }
25 25
26 -</script>  
27 \ No newline at end of file 26 \ No newline at end of file
  27 +</script>