CrazyIter_Bin 5 months ago
parent
commit
032fc1237a

+ 93 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/BaseController.cs

@@ -0,0 +1,93 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace IES.ExamServer.Controllers
+{
+    public class BaseController : ControllerBase
+    {
+        public BaseController()
+        {
+
+
+        }
+        public string GetIP()
+        {
+            var IpPort = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+
+            if (string.IsNullOrEmpty(IpPort))
+            {
+                IpPort = $"{HttpContext.Connection.RemoteIpAddress}";
+            }
+            if (IpPort.Contains("::"))
+            {
+                IpPort = "127.0.0.1";
+            }
+            return IpPort;
+        }
+        public string GetCookie(string key)
+        {
+            IRequestCookieCollection cookies = HttpContext.Request.Cookies;
+            string value = "";
+            if (cookies != null)
+            {
+                foreach (var ck in cookies)
+                {
+                    if (ck.Key.Equals(key))
+                    {
+                        value = ck.Value;
+                        break;
+                    }
+                }
+            }
+            return value;
+        }
+        /// <summary>
+        /// 取得AuthToken權杖資訊
+        /// </summary>        
+        /// <param name="key">Key Name</param>
+        /// <returns></returns>
+        public (string id, string name, string picture, string school, string keyData) GetAuthTokenInfo(string? key = null)
+        {
+            object? keyData = null;
+            HttpContext.Items.TryGetValue("ID", out object? id);
+            HttpContext.Items.TryGetValue("Name", out object? name);
+            HttpContext.Items.TryGetValue("Picture", out object? picture);
+            HttpContext.Items.TryGetValue("School", out object? school);
+            if (!string.IsNullOrWhiteSpace(key))
+            {
+                HttpContext.Items.TryGetValue(key, out keyData);
+            }
+            return ($"{id}", $"{name}", $"{picture}", $"{school}", $"{keyData}");
+        }
+
+        /// <summary>
+        /// 取得驗證金鑰,Authorization
+        /// </summary>        
+        public string GetToken()
+        {
+            return HttpContext.Request.Headers["Authorization"].ToString();
+        }
+
+        /// <summary>
+        /// 取得JWT驗證金鑰,Authorization Bearer
+        /// </summary>
+        /// <param name="httpContext"></param>
+        /// <returns></returns>
+        public string GetJwtToken()
+        {
+            var token = string.Empty;
+            string authorization = HttpContext.Request.Headers["Authorization"].ToString();
+            if (!string.IsNullOrWhiteSpace(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
+            {
+                token = authorization.Substring("Bearer ".Length).Trim();
+            }
+            return token;
+        }
+
+
+
+        public readonly int code = 0;
+        public readonly string msg = "OK";
+
+
+    }
+}

+ 23 - 18
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/InitController.cs

@@ -8,20 +8,21 @@ using IES.ExamServer.Helper;
 using System.DrawingCore.Imaging;
 using System.DrawingCore;
 using System.IdentityModel.Tokens.Jwt;
+using IES.ExamServer.Services;
 
 namespace IES.ExamServer.Controllers
 {
     [ApiController]
-    [Route("init")]
+    [Route("index")]
   
-    public class InitController : ControllerBase
+    public class IndexController : BaseController
     {
         private readonly IConfiguration _configuration;
         private readonly IHttpClientFactory _httpClientFactory;
         private readonly IMemoryCache _memoryCache;
-        private readonly ILogger<InitController> _logger;
+        private readonly ILogger<IndexController> _logger;
 
-        public InitController(ILogger<InitController> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory, IMemoryCache memoryCache)
+        public IndexController(ILogger<IndexController> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory, IMemoryCache memoryCache)
         {
             _logger = logger;
             _configuration=configuration;
@@ -29,30 +30,34 @@ namespace IES.ExamServer.Controllers
             _memoryCache=memoryCache;
         }
         [HttpPost("device")]
-        public async Task<IActionResult> Device()
+        public async Task<IActionResult> Device(JsonElement json )
         {
             int code = 0;
             string msg = string.Empty;
             try
             {
-
+                string ip=   GetIP();
+                json.TryGetProperty("fp", out JsonElement fp);
+                var device = IndexService.GetDeviceInit(HttpContext, $"{fp}", ip, _memoryCache);
+                int hybrid = 0;
                 _memoryCache.TryGetValue(Constant._KeyServerCenter, out JsonNode? data);
+                _memoryCache.TryGetValue(Constant._KeyServerDevice, out ServerDevice? server);
                 if (data!=null)
                 {
-                    return Ok(new { code = 200, msg = "云端服务连接成功!", data = data });
+                    hybrid=1;
+                    msg="云端服务连接成功!";
+                    return Ok(new { code = 200, msg, data = new { hybrid, device, centerUrl = data["centerUrl"], region = data["region"],ip= data["ip"] , nowtime = DateTimeOffset.Now.ToUnixTimeMilliseconds(), server } });
                 }
-                else
-                {
-                    code=500;
+                else {
                     msg="云端服务未连接!";
+                    return Ok(new { code = 200, msg, data = new { hybrid, device,  centerUrl = "", region = "局域网·内网", ip = ip, nowtime= DateTimeOffset.Now.ToUnixTimeMilliseconds(), server } });
                 }
-
-
+                
             }
             catch (Exception ex)
             {
                 code=500;
-                msg="云端服务未连接!";
+                msg="服务端异常!";
             }
             return Ok(new { code, msg });
         }
@@ -151,7 +156,7 @@ namespace IES.ExamServer.Controllers
                         jwt.Payload.TryGetValue("name", out object? name);
                         jwt.Payload.TryGetValue("picture", out object? picture);
                         _memoryCache.Set($"Teacher:{id}", new LoginTeacher { id=id, name=$"{name}", implicit_token= token, picture=$"{picture}", schools=schools, x_auth_token=x_auth_token });
-                        return Ok(new { implicit_token = token, x_auth_token = x_auth_token, schools = schools });
+                        return Ok(new { code=200, implicit_token = token, x_auth_token = x_auth_token, schools = schools });
                     }
                     else
                     {
@@ -189,7 +194,7 @@ namespace IES.ExamServer.Controllers
             string randomCode = "";
             switch (true)
             {
-                case bool when $"{type}".Equals("skiaqrcode"):
+                case bool when $"{type}".Equals("qrcode"):
                     {
                         //.NET Core使用SkiaSharp快速生成二维码  https://cloud.tencent.com/developer/article/2336486
 
@@ -198,11 +203,11 @@ namespace IES.ExamServer.Controllers
                         randomCode = $"{random.Next(1000, 9999)}";
                         string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
                         string content = $"{CenterUrl}/joinSchool?schoolCode=login:{randomCode}&m=%E7%99%BB%E5%BD%95&o=1";
-                        var  str= QRCodeHelper.GenerateQRCode(content, 200, 200);
+                        var  str= QRCodeHelper.GenerateQRCode(content, 300, 300,QRCodeHelper.logo);
                         qrcode = $"data:image/png;base64,{str}";
                         return Ok(new { code = 200, randomCode = randomCode, qrcode, type });
                     }
-                case bool when $"{type}".Equals("qrcode"):
+                case bool when $"{type}".Equals("xqrcode"):
                     {
                         // 生成二维码图片
                         Random random = new Random();
@@ -225,7 +230,7 @@ namespace IES.ExamServer.Controllers
                         {
                             string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
                             string url = $"{CenterUrl}/core/sendsms/pin";
-                            HttpResponseMessage message = await _httpClientFactory.CreateClient().PostAsJsonAsync(url, new { });
+                            HttpResponseMessage message = await _httpClientFactory.CreateClient().PostAsJsonAsync(url, new { area=json["area"], to = json["to"], lang="zh-cn" });
                             if (message.IsSuccessStatusCode)
                             {
                                 string content = await message.Content.ReadAsStringAsync();

+ 38 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/CollectionHelper.cs

@@ -0,0 +1,38 @@
+namespace IES.ExamServer.Helpers
+{
+    public static class CollectionHelper
+    {
+        /// <summary>
+        /// 判断集合是否为空
+        /// </summary>
+        /// <param name="collection"></param>
+        /// <returns></returns>
+        public static bool IsEmpty<T>(this IEnumerable<T> collection)
+        {
+            if (collection != null && collection.Any())
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+        /// <summary>
+        /// 判断集合是否不为空
+        /// </summary>
+        /// <param name="collection"></param>
+        /// <returns></returns>
+        public static bool IsNotEmpty<T>(this IEnumerable<T> collection)
+        {
+            if (collection != null && collection.Any())
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+}

+ 1 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/Constant.cs

@@ -9,5 +9,6 @@ namespace IES.ExamServer.Helper
     public static class Constant
     {
         public static string _KeyServerCenter = "Server:Center:Data";
+        public static string _KeyServerDevice = "Server:Device:Info";
     }
 }

File diff suppressed because it is too large
+ 46 - 58
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/QRCodeHelper.cs


+ 134 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ShaHashHelper.cs

@@ -0,0 +1,134 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace IES.ExamServer.Helpers
+{
+    public sealed class ShaHashHelper
+    {
+        public static string GetSHA1(string Code)
+        {
+            var resbuffer = Encoding.Default.GetBytes(Code);
+            HashAlgorithm iSha = new SHA1CryptoServiceProvider();
+            resbuffer = iSha.ComputeHash(resbuffer);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(strRes);
+        }
+        public static string GetSHA1(byte[] buffer)
+        {
+            var resbuffer = buffer;
+            HashAlgorithm iSha = new SHA1CryptoServiceProvider();
+            resbuffer = iSha.ComputeHash(buffer);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            // return Convert.ToBase64String(strRes);
+        }
+        public static string GetSHA1(Stream stream)
+        {
+            byte[] buffer = new byte[stream.Length];
+
+            stream.Read(buffer, 0, buffer.Length);
+            // stream.Close();
+            var resbuffer = buffer;
+            HashAlgorithm iSha = new SHA1CryptoServiceProvider();
+            resbuffer = iSha.ComputeHash(buffer);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            // return Convert.ToBase64String(strRes);
+        }
+        public static string GetSHA1(string Code, string SecretKey)
+        {
+            HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(SecretKey));
+            byte[] resbuffer = hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(Code));
+
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(rstRes); 
+        }
+        public static string GetSHA1(byte[] buffer, string SecretKey)
+        {
+            HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(SecretKey));
+            byte[] resbuffer = hmacsha1.ComputeHash(buffer);
+
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //eturn Convert.ToBase64String(buffer);
+        }
+        public static string GetSHA256(byte[] buffer)
+        {
+            SHA256Managed Sha256 = new SHA256Managed();
+            byte[] resbuffer = Sha256.ComputeHash(buffer);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(retval);
+
+        }
+
+        public static string GetSHA256(string Code)
+        {
+            SHA256Managed Sha256 = new SHA256Managed();
+            byte[] resbuffer = Sha256.ComputeHash(Encoding.UTF8.GetBytes(Code));
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(retval);
+        }
+
+        public static string GetSHA256(byte[] buffer, string SecretKey)
+        {
+            byte[] messageBytes = buffer;
+            byte[] keyByte = Encoding.UTF8.GetBytes(SecretKey);
+            var hmacsha256 = new HMACSHA256(keyByte);
+            byte[] resbuffer = hmacsha256.ComputeHash(messageBytes);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(hashmessage);
+        }
+
+        public static string GetSHA256(string Code, string SecretKey)
+        {
+            byte[] messageBytes = Encoding.UTF8.GetBytes(Code);
+            byte[] keyByte = Encoding.UTF8.GetBytes(SecretKey);
+            var hmacsha256 = new HMACSHA256(keyByte);
+            byte[] resbuffer = hmacsha256.ComputeHash(messageBytes);
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < resbuffer.Length; i++)
+            {
+                builder.Append(resbuffer[i].ToString("x2"));
+            }
+            return builder.ToString();
+            //return Convert.ToBase64String(resbuffer);
+        }
+    }
+}

+ 1 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/IES.ExamServer.csproj

@@ -34,6 +34,7 @@
 		<PackageReference Include="LiteDB" Version="5.0.21" />
 		<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
 		<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
+		<PackageReference Include="System.Management" Version="6.0.2" />
 		<PackageReference Include="VueCliMiddleware" Version="6.0.0" />
 		<PackageReference Include="ZXing.Net.Bindings.ZKWeb.System.Drawing" Version="0.16.7" />
 	</ItemGroup>

+ 21 - 3
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Program.cs

@@ -1,12 +1,15 @@
 using IES.ExamServer.DI;
 using IES.ExamServer.DI.SignalRHost;
 using IES.ExamServer.Helper;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Hosting.Server;
 using Microsoft.AspNetCore.SpaServices;
 using Microsoft.AspNetCore.StaticFiles;
 using Microsoft.Extensions.Caching.Memory;
 using System.Text.Json;
 using System.Text.Json.Nodes;
 using VueCliMiddleware;
+using IES.ExamServer.Services;
 
 namespace IES.ExamServer
 {
@@ -106,6 +109,9 @@ namespace IES.ExamServer
             IHttpClientFactory? clientFactory = app.Services.GetRequiredService<IHttpClientFactory>();
             LiteDBFactory liteDBFactory = app.Services.GetRequiredService<LiteDBFactory>();
             JsonNode? data = null;
+            int hybrid = 0;
+            string remote = "127.0.0.1";
+            string region = "局域网·内网";
             try
             {
                 string? CenterUrl = builder.Configuration.GetValue<string>("ExamServer:CenterUrl");
@@ -118,14 +124,26 @@ namespace IES.ExamServer
                     data = JsonSerializer.Deserialize<JsonNode>(content);
                     data!["centerUrl"]=CenterUrl;
                     cache.Set(Constant._KeyServerCenter, data);
-                    SystemInfo? system = JsonSerializer.Deserialize<SystemInfo>(data);
-                    system!.id= $"{DateTimeOffset.Now.ToUnixTimeMilliseconds()}";
-                    liteDBFactory.GetLiteDatabase().GetCollection<SystemInfo>("System").Insert(system);
+                    remote=$"{data["ip"]}";
+                    region=$"{data["region"]}";
+                    hybrid =1;
                 }
             }
             catch (Exception ex)
             {
+                //云端服务连接失败
+                hybrid = 0;
             }
+            var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
+            lifetime.ApplicationStarted.Register(() =>
+            {
+
+                var server = app.Services.GetService<IServer>();
+                var d = server?.Features.Get<IServerAddressesFeature>();
+                IEnumerable<string>? _url = server?.Features.Get<IServerAddressesFeature>()?.Addresses;
+                ServerDevice serverDevice = IndexService.GetServerDevice(remote, region, _url);
+                cache.Set(Constant._KeyServerDevice, serverDevice);
+            });
             app.Run();
         }
     }

+ 319 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Services/IndexService.cs

@@ -0,0 +1,319 @@
+using IES.ExamServer.Helpers;
+using Microsoft.Extensions.Caching.Memory;
+using System.Diagnostics;
+using System.Net.NetworkInformation;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.RegularExpressions;
+using System.Management;
+
+namespace IES.ExamServer.Services
+{
+    public static class IndexService
+    {
+        public static ServerDevice GetServerDevice( string remote,string region,  IEnumerable<string>? _url)
+        {
+            string hostName = $"{Environment.UserName}-{Dns.GetHostName()}";
+            string os = RuntimeInformation.OSDescription;
+            //获取当前客户端的服务端口
+          
+            ServerDevice device = new ServerDevice { name =hostName, os= os,region=region,remote=remote };
+            int CpuCoreCount = 0;
+            long MenemorySize = 0;
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                // 获取CPU核心数
+                //int processorCount = Environment.ProcessorCount;
+                //Console.WriteLine("CPU 核心数: " + processorCount);
+                using (ManagementClass managementClass = new ManagementClass("Win32_Processor"))
+                {
+                    using (ManagementObjectCollection managementObjectCollection = managementClass.GetInstances())
+                    {
+                        foreach (ManagementObject managementObject in managementObjectCollection)
+                        {
+                            CpuCoreCount += Convert.ToInt32(managementObject.Properties["NumberOfLogicalProcessors"].Value);
+                        }
+                    }
+                }
+                using (ManagementClass mc = new ManagementClass("Win32_ComputerSystem"))
+                {
+                    using (ManagementObjectCollection moc = mc.GetInstances())
+                    {
+                        foreach (ManagementObject mo in moc)
+                        {
+                            if (mo["TotalPhysicalMemory"]!= null)
+                            {
+                                MenemorySize = Convert.ToInt64(mo["TotalPhysicalMemory"]);
+                            }
+                        }
+                    }
+                }
+            }
+            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+            {
+                //int processorCount = Environment.ProcessorCount;
+                // Console.WriteLine("CPU 核心数: " + processorCount);
+                string[] cpu_lines = File.ReadAllLines("/proc/cpuinfo");
+                CpuCoreCount= cpu_lines.Count(line => line.StartsWith("processor", StringComparison.OrdinalIgnoreCase));
+                string[] mem_lines = File.ReadAllLines("/proc/meminfo");
+                var match = mem_lines.FirstOrDefault(line => line.StartsWith("MemTotal:"));
+                if (match != null)
+                {
+                    var matchResult = Regex.Match(match, @"\d+");
+                    if (matchResult.Success)
+                    {
+                        MenemorySize=  long.Parse(matchResult.Value);
+                    }
+                }
+            }
+            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+            {
+                using (var process = new Process())
+                {
+                    process.StartInfo.FileName = "/usr/sbin/sysctl";
+                    process.StartInfo.Arguments = "-n hw.ncpu";
+                    process.StartInfo.RedirectStandardOutput = true;
+                    process.StartInfo.UseShellExecute = false;
+                    process.Start();
+                    string output = process.StandardOutput.ReadToEnd().Trim();
+                    int coreCount;
+                    if (int.TryParse(output, out coreCount))
+                    {
+                        CpuCoreCount= coreCount;
+                    }
+                }
+                using (var process = new Process())
+                {
+                    process.StartInfo.FileName = "/usr/sbin/sysctl";
+                    process.StartInfo.Arguments = "-n hw.memsize";
+                    process.StartInfo.RedirectStandardOutput = true;
+                    process.StartInfo.UseShellExecute = false;
+                    process.Start();
+                    string output = process.StandardOutput.ReadToEnd().Trim();
+                    long memorySize;
+                    if (long.TryParse(output, out memorySize))
+                    {
+                        MenemorySize=  memorySize;
+                    }
+                }
+            }
+
+            //Console.WriteLine("CPU 核心数: " + CpuCoreCount+",RAM 大小:"+MenemorySize);
+            
+            device.cpu=CpuCoreCount;
+            device.ram=MenemorySize;
+            var nics = NetworkInterface.GetAllNetworkInterfaces();
+            foreach (var nic in nics)
+            {
+                if (nic.OperationalStatus == OperationalStatus.Up)
+                {
+                    var name = $"{nic.Name}-{nic.Description}";
+                    var mac = nic.GetPhysicalAddress().ToString();
+                    var properties = nic.GetIPProperties();
+                    var unicastAddresses = properties.UnicastAddresses;
+                    foreach (var unicast in unicastAddresses)
+                    {
+                        if (unicast.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+                        {
+                            var ip = unicast.Address.ToString();
+                            Network network = new Network() { mac=mac, ip=ip, name= name };
+                            if (!string.IsNullOrWhiteSpace(mac.ToString())  && !mac.Equals("000000000000"))
+                            {
+                                device.networks.Add(network);
+                            }
+                        }
+                    }
+                }
+            }
+            if (_url!.IsNotEmpty())
+            {
+                List<int> ports = new List<int>();
+                foreach (var url in _url)
+                {
+                    Uri uri = new Uri(url);
+                    ports.Add(uri.Port);
+                }
+                device.port= string.Join(",", ports);
+            }
+            else
+            {
+                throw new Exception("未获取到端口信息!");
+            }
+            string hashData = ShaHashHelper.GetSHA1($"{device.name}-{device.remote}-{device.port}-{device.os}-{string.Join(",", device.networks.Select(x => $"{x.mac}-{x.ip}"))}");
+            device.deviceId=hashData;
+            return device;
+        }
+
+
+
+
+
+        /// <summary>
+        /// 初始化设备
+        /// </summary>
+        /// <param name="httpContext"></param>
+        /// <param name="fingerprint">浏览器指纹</param>
+        /// <param name="IP"></param>
+        /// <param name="device_timeSpan"></param>
+        /// <param name="_azureRedis"></param>
+        /// <returns></returns>
+        public static   string GetDeviceInit(this HttpContext httpContext, string fingerprint, string IP, IMemoryCache _memoryCache)
+        {
+            string device = $"{fingerprint}-{IP}";
+            List<string> cookieString = new List<string>();
+            var cookie = httpContext.Request.Cookies;
+            int status = 1;
+            if (cookie != null)
+            {
+                ///设备是否存在
+                foreach (var ck in cookie)
+                {
+                    if (ck.Key.Equals("device"))
+                    {
+                        if (device.Contains("-") && device.Contains("."))
+                        {
+                            //如果匹配的是fingerprint-IP 则是已经存在的。
+                            if (ck.Value.Equals(device))
+                            {
+                                //redis如果存在则
+                                _memoryCache.TryGetValue<JsonNode>($"device:{fingerprint}:{IP}", out JsonNode device_exist);
+                                // 返回的则应该是ck.Value=exist_device_exist的数据
+                                if (device_exist!=null)
+                                {
+                                    if (!string.IsNullOrWhiteSpace($"{device_exist["device"]}"))
+                                    {
+                                        //0是代表指纹和IP匹配,正常返回的
+                                        status = 1;
+                                    }
+                                    else
+                                    {
+                                        //需要新建 fingerprint-IP
+                                        status = 1;
+                                    }
+                                }
+                                else
+                                {
+                                    status = 1;
+                                }
+
+                            }
+                            else
+                            {
+                                string ck_ip = ck.Value.Split("-")[1];
+                                if (ck_ip.Equals(IP))
+                                {
+                                    //传入的指纹和cookie的不一致,仍然以cookie的为准。
+                                    status = 1;
+                                    fingerprint = ck.Value.Split("-").First();
+                                    device = ck.Value;
+                                }
+                            }
+                        }
+
+                        else
+                        {
+                            //如果匹配的是fingerprint则是一个新的设备。
+                            if (ck.Value.Equals(fingerprint))
+                            {
+                                //检查设备是否被占用
+                                //var device_exist = _azureRedis.GetRedisClient(8).HashExists($"device:{fingerprint}", IP);
+                                _memoryCache.TryGetValue<JsonNode>($"device:{fingerprint}:{IP}", out JsonNode device_exist);
+                                if (device_exist!=null)
+                                {
+                                    //需要新建 sha1(fingerprint+uuid)-IP
+                                    status = 2;
+                                }
+                                else
+                                {
+                                    //0是代表指纹和IP匹配,正常返回的
+                                    status = 1;
+
+                                }
+                            }
+                            else
+                            {
+                                //匹配的都不是,新设备。
+                                status = 1;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        cookieString.Add($"{ck.Key}{ck.Value}");
+                    }
+                }
+            }
+            /*
+                httpContext.Request.Headers.TryGetValue("accept-language", out var accept_language);
+                httpContext.Request.Headers.TryGetValue("sec-ch-ua", out var chua);
+                httpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
+                httpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
+                httpContext.Request.Headers.TryGetValue("accept", out var accept);
+                httpContext.Request.Headers.TryGetValue("accept-encoding", out var accept_encoding);
+                device = ShaHashHelper.GetSHA1($"{IP}{accept_language}{chua}{platform}{useragent}{accept}{accept_encoding}{string.Join("", cookieString)}");
+             */
+            if (status == 2)
+            {
+                fingerprint = ShaHashHelper.GetSHA1(fingerprint + Guid.NewGuid().ToString());
+                device = $"{fingerprint}-{IP}";
+            }
+            //else if (status == 1)
+            //{
+            //    device = $"{fingerprint}-{IP}";
+            //}
+            //await _azureRedis.GetRedisClient(8).HashSetAsync($"device:{fingerprint}", IP, new { device }.ToJsonString());
+            //await _azureRedis.GetRedisClient(8).KeyExpireAsync($"device:{fingerprint}", device_timeSpan);
+            _memoryCache.Set($"device:{fingerprint}:{IP}", new { device });
+            httpContext.Response.Cookies.Append("device", device, new CookieOptions { HttpOnly = true, MaxAge = new TimeSpan(24 * 7, 0, 0) });
+            return device;
+        }
+    }
+    public class ServerDevice
+    { 
+        
+        /// <summary>
+        /// 设备id
+        /// </summary>
+        public string? deviceId { get; set; }
+        /// <summary>
+        /// 机器名
+        /// </summary>
+        public string? name { get; set; }
+        /// <summary>
+        /// 操作系统
+        /// </summary>
+        public string? os { get; set; }
+        /// <summary>
+        /// CPU核心数量
+        /// </summary>
+        public int cpu { get; set; } 
+        /// <summary>
+        /// 内存大小
+        /// </summary>
+        public long ram { get; set;}
+        /// <summary>
+        /// 远程ip
+        /// </summary>
+        public string? remote { get; set; }
+        /// <summary>
+        /// 端口,可能有多个端口
+        /// </summary>
+        public string? port { get; set; }
+        /// <summary>
+        /// 地区
+        /// </summary>
+        public string? region { get; set; }
+        /// <summary>
+        /// 网卡 IP信息
+        /// </summary>
+        public List<Network> networks { get; set; } = new List<Network>();
+    }
+    public class Network
+    {
+        public string? name { get; set; }
+        public string? mac { get; set; }
+        public string? ip { get; set; }
+    }
+}

+ 3 - 3
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -1444,8 +1444,8 @@ const LANG_ZH_CN = {
             joinBtn: '立即加入',
             errorTile: '信息错误',
             errorContent: '课程名单获取失败,请重新扫码加入!',
-            joinOk: '加入成功',
-            joinErr: '加入失败',
+            joinOk: '成功',
+            joinErr: '失败',
             joinLock: "课程名单未开放加入",
             getListErr: '获取名单信息失败',
             hasJoin: '课程加入成功!',
@@ -2196,7 +2196,7 @@ const LANG_ZH_CN = {
         toPhone: '前往绑定>>>',
         phoneSuccess: '手机号绑定已完成!',
         hasBanding: '已绑定',
-        verifySchoolTitle: '加入学校',
+        verifySchoolTitle: '',
         verifySchool: '暂未加入学校',
         toSchool: '加入学校>>>',
         schoolSuccess: '您已加入学校!',

+ 1 - 1
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -1804,7 +1804,7 @@ namespace TEAMModelOS.Controllers.Client
                     //取得學校資訊
                     if (string.IsNullOrWhiteSpace(request.school)) return BadRequest();
                     await foreach (var  item in db.GetContainer(Constant.TEAMModelOS, Constant.School).GetItemQueryStreamIteratorSql(
-                        queryText: $"SELECT TOP 1 c.id, c.size, c.tsize, c.timeZone FROM c WHERE c.id = '{request.school}'",
+                        queryText: $"SELECT TOP 1 c.id, c.size, c.tsize, c.timeZone ,c.areaId FROM c WHERE c.id = '{request.school}'",
                         requestOptions: new() { PartitionKey = new("Base") }))
                     {
                         using var json = await JsonDocument.ParseAsync(item.Content);

+ 14 - 8
TEAMModelOS/Controllers/System/CoreController.cs

@@ -427,6 +427,7 @@ namespace TEAMModelOS.Controllers
         public async Task<IActionResult> SendSmsCheck(JsonNode request)
         {
             string msg = string.Empty;
+
             int timezone = 8;
             if (HttpContext.Request.Headers.TryGetValue("Time-Zone", out var Time_Zone) && int.TryParse(Time_Zone, out int tz))
             {
@@ -434,10 +435,11 @@ namespace TEAMModelOS.Controllers
             }
             var pin_code = request["pin_code"];
             var account = request["account"];
+            TmdidImplicit implicit_token = null;
             var loginData= await _coreAPIHttpService.Auth2Login($"{pin_code}", $"{account}", _option.Location, _configuration, _dingDing);
             if (loginData.code.Equals(HttpStatusCode.OK))
             {
-                TmdidImplicit implicit_token = null;
+               
                 var node = JsonSerializer.Deserialize<JsonNode>(loginData.content);
                 if (node?["id_token"]!=null)
                 {
@@ -448,16 +450,20 @@ namespace TEAMModelOS.Controllers
                     if (node?["error"]!=null  && $"{node?["error"]}".Equals("2"))
                     {
                         string mobile = $"{account}".Split("-").Last();
-                        var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
-                        var location = _option.Location;
-                        implicit_token = await _coreAPIHttpService.Implicit(
-                            new Dictionary<string, string>()
-                            {
+                        var coreUser = await _coreAPIHttpService.GetUserInfo(new Dictionary<string, string> { { "key", $"{mobile}" } }, _option.Location, _configuration);
+                        if (coreUser!=null)
+                        {
+                            var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                            var location = _option.Location;
+                            implicit_token = await _coreAPIHttpService.Implicit(
+                                new Dictionary<string, string>()
+                                {
                                     { "grant_type", "implicit" },
                                     { "client_id",clientID },
-                                    { "account",mobile },
+                                    { "account",coreUser.id },
                                     { "nonce",Guid.NewGuid().ToString()}
-                            }, location, _configuration);
+                                }, location, _configuration);
+                        }
                     }
                     else {
                         msg=$"验证失败!{loginData.content}";

+ 1 - 0
TEAMModelOS/Controllers/Third/IRS/ThirdIRSController.cs

@@ -52,6 +52,7 @@ namespace TEAMModelOS.Controllers
             {"habook",("school","ThirdIRS_139zhxy") },
             {"21eab496-9260-4881-a955-1eb5d3d04b88",("area","ThirdIRS_139zhxy") },
             {"mzhmxx",("school","ThirdIRS_139zhxy") }
+            //  ,{"ghxyfs",("school","ThirdIRS_139zhxy") }
         };
         
         public AzureCosmosFactory _azureCosmos;