OCPPWSServer.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. 
  2. using EVCB_OCPP.Domain;
  3. using EVCB_OCPP.WSServer.Service;
  4. using Microsoft.EntityFrameworkCore;
  5. using Microsoft.EntityFrameworkCore.Internal;
  6. using Microsoft.Extensions.Configuration;
  7. using Microsoft.Extensions.DependencyInjection;
  8. using Microsoft.Extensions.Logging;
  9. using MongoDB.Driver.Core.Servers;
  10. using OCPPPackage.Profiles;
  11. using SuperWebSocket;
  12. using SuperWebSocket.SubProtocol;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Configuration;
  16. using System.Linq;
  17. using System.Net;
  18. using System.Net.Security;
  19. using System.Security.Cryptography.X509Certificates;
  20. using System.Text;
  21. namespace OCPPServer.Protocol;
  22. public class OCPPWSServer : WebSocketServer<ClientData>
  23. {
  24. private readonly ILogger logger;
  25. private readonly IConfiguration configuration;
  26. private readonly IMainDbService mainDbService;
  27. /// <summary>
  28. /// 可允許連線Clinet數
  29. /// </summary>
  30. public int connectNum { get; set; }
  31. /// <summary>
  32. /// 是否限制連線Clinet數
  33. /// </summary>
  34. public bool beConnectLimit { get; set; }
  35. /// <summary>
  36. /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
  37. /// </summary>
  38. /// <param name="subProtocols">The sub protocols.</param>
  39. public OCPPWSServer(
  40. IConfiguration configuration,
  41. IMainDbService mainDbService,
  42. ILogger<OCPPWSServer> logger)
  43. : base(new List<ISubProtocol<ClientData>>())
  44. {
  45. this.configuration = configuration;
  46. this.mainDbService = mainDbService;
  47. this.logger = logger;
  48. }
  49. /// <summary>
  50. /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
  51. /// </summary>
  52. /// <param name="subProtocol">The sub protocol.</param>
  53. //public OCPPWSServer(ISubProtocol<ClientData> subProtocol, IServiceProvider serviceProvider)
  54. // : base(subProtocol)
  55. //{
  56. // this.configuration = serviceProvider.GetService<IConfiguration>();
  57. // logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
  58. //}
  59. /// <summary>
  60. /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
  61. /// </summary>
  62. //public OCPPWSServer(IServiceProvider serviceProvider)
  63. // : base(new List<ISubProtocol<ClientData>>())
  64. //{
  65. // this.configuration = serviceProvider.GetService<IConfiguration>();
  66. // logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
  67. //}
  68. protected override bool ValidateClientCertificate(ClientData session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
  69. {
  70. // Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " ValidateClientCertificate", sslPolicyErrors));
  71. return true;
  72. // return base.ValidateClientCertificate(session, sender, certificate, chain, sslPolicyErrors);
  73. }
  74. protected override bool ValidateHandshake(ClientData session, string origin)
  75. {
  76. session.ISOCPP20 = session.SecWebSocketProtocol.ToLower().Contains("ocpp2.0");
  77. int securityProfile = 0;
  78. string authorizationKey = string.Empty;
  79. if (string.IsNullOrEmpty(session.Path))
  80. {
  81. //logger.Log();
  82. logger.LogWarning("===========================================");
  83. logger.LogWarning("session.Path EMPTY");
  84. logger.LogWarning("===========================================");
  85. }
  86. string[] words = session.Path.Split('/');
  87. session.ChargeBoxId = words.Last();
  88. if (configuration["MaintainMode"] == "1")
  89. {
  90. session.ChargeBoxId = session.ChargeBoxId + "_2";
  91. }
  92. logger.LogInformation(string.Format("ValidateHandshake: {0}", session.Path));
  93. bool isExistedSN = false;
  94. bool authorizated = false;
  95. var info = mainDbService.GetMachineIdAndCustomerInfo(session.ChargeBoxId).Result;
  96. //var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefault();
  97. //session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault();
  98. //session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId;
  99. //session.MachineId = machine == null ? String.Empty : machine.Id;
  100. //isExistedSN = machine == null ? false : true;
  101. session.CustomerName = info.CustomerName;
  102. session.CustomerId = info.CustomerId;
  103. session.MachineId = info.MachineId;
  104. isExistedSN = !string.IsNullOrEmpty(info.MachineId);// machine == null ? false : true;
  105. if (!isExistedSN)
  106. {
  107. StringBuilder responseBuilder = new StringBuilder();
  108. responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
  109. (int)HttpStatusCode.NotFound, @"Not Found");
  110. responseBuilder.AppendWithCrCf();
  111. string sb = responseBuilder.ToString();
  112. byte[] data = Encoding.UTF8.GetBytes(sb);
  113. ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
  114. logger.LogInformation(sb);
  115. return false;
  116. }
  117. //var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
  118. // .Select(x => x.ConfigureSetting).FirstOrDefault();
  119. var configVaule = mainDbService.GetMachineSecurityProfile(session.ChargeBoxId).Result;
  120. int.TryParse(configVaule, out securityProfile);
  121. if (session.ISOCPP20)
  122. {
  123. // 1.6 server only support change server function
  124. securityProfile = 0;
  125. }
  126. if (securityProfile == 3 && session.UriScheme == "ws")
  127. {
  128. StringBuilder responseBuilder = new StringBuilder();
  129. responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
  130. (int)HttpStatusCode.Unauthorized, @"Unauthorized");
  131. responseBuilder.AppendWithCrCf();
  132. string sb = responseBuilder.ToString();
  133. byte[] data = Encoding.UTF8.GetBytes(sb);
  134. ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
  135. logger.LogInformation(sb);
  136. return false;
  137. }
  138. if ((securityProfile == 1 || securityProfile == 2))
  139. {
  140. if (securityProfile == 2 && session.UriScheme == "ws")
  141. {
  142. authorizated = false;
  143. }
  144. if (session.Items.ContainsKey("Authorization") || session.Items.ContainsKey("authorization"))
  145. {
  146. //authorizationKey = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
  147. // .Select(x => x.ConfigureSetting).FirstOrDefault();
  148. authorizationKey = mainDbService.GetMachineAuthorizationKey(session.ChargeBoxId).Result;
  149. if (session.ISOCPP20)
  150. {
  151. // 1.6 server only support change server function
  152. securityProfile = 0;
  153. }
  154. logger.LogInformation("***********Authorization ");
  155. if (!string.IsNullOrEmpty(authorizationKey))
  156. {
  157. string base64Encoded = session.Items.ContainsKey("Authorization") ? session.Items["Authorization"].ToString().Replace("Basic ", "") : session.Items["authorization"].ToString().Replace("Basic ", "");
  158. byte[] data = Convert.FromBase64String(base64Encoded);
  159. string[] base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':');
  160. logger.LogInformation("***********Authorization " + System.Text.ASCIIEncoding.ASCII.GetString(data));
  161. if (base64Decoded.Count() == 2 && base64Decoded[0] == session.ChargeBoxId && base64Decoded[1] == authorizationKey)
  162. {
  163. authorizated = true;
  164. }
  165. }
  166. }
  167. else
  168. {
  169. authorizated = true;
  170. }
  171. if (!authorizated)
  172. {
  173. StringBuilder responseBuilder = new StringBuilder();
  174. responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
  175. (int)HttpStatusCode.Unauthorized, @"Unauthorized");
  176. responseBuilder.AppendWithCrCf();
  177. string sb = responseBuilder.ToString();
  178. byte[] data = Encoding.UTF8.GetBytes(sb);
  179. ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
  180. logger.LogInformation(sb);
  181. return false;
  182. }
  183. }
  184. return true;
  185. }
  186. }