huanghb 5 月之前
父節點
當前提交
b87db088cb

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

@@ -45,7 +45,7 @@ namespace IES.ExamServer.Controllers
         /// </summary>        
         /// <param name="key">Key Name</param>
         /// <returns></returns>
-        public (string? id, string? name, string? picture, string? school,string? scope ,string? timeZone,List<string> rolse, string? keyData) GetAuthTokenInfo(string? key = null)
+        public (string id, string? name, string picture, string school,string scope ,string timeZone,List<string> rolse, string keyData) GetAuthTokenInfo(string? key = null)
         {
             object? keyData = null;
             HttpContext.Items.TryGetValue("ID", out object? id);

+ 12 - 2
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/IndexController.cs

@@ -10,6 +10,7 @@ using System.DrawingCore;
 using System.IdentityModel.Tokens.Jwt;
 using IES.ExamServer.Services;
 using IES.ExamServer.DI;
+using IES.ExamLib.Models;
 
 namespace IES.ExamServer.Controllers
 {
@@ -94,6 +95,16 @@ namespace IES.ExamServer.Controllers
                     JsonNode? jsonNode = null;
                     switch (true)
                     {
+                        //跳过忽略,但是仍然要以访客身份登录
+                        case bool when $"{type}".Equals(ExamConstant.ScopeVisitor):
+                            {
+                                string id = $"{DateTimeOffset.Now.ToUnixTimeSeconds()}";
+                                string name = $"访客教师-{Random.Shared.Next(100, 999)}";
+                                x_auth_token = JwtAuthExtension.CreateAuthToken("www.teammodel.cn",id ,name,null
+                                    ,ExamConstant.JwtSecretKey,ExamConstant.ScopeVisitor,8,null,new string[] { "visitor" }, expire: 1);
+                                _memoryCache.Set($"Teacher:{id}", new LoginTeacher { id = id, name = $"{name}", implicit_token = token, picture = null, schools = schools, x_auth_token = x_auth_token });
+                                return Ok(new { code = 200,x_auth_token = x_auth_token });
+                            }
                         case bool when $"{type}".Equals("qrcode"):
                             {
                                 string randomCode = $"{json["randomCode"]}";
@@ -106,7 +117,6 @@ namespace IES.ExamServer.Controllers
                                     if (!string.IsNullOrWhiteSpace(content))
                                     {
                                         jsonNode = JsonSerializer.Deserialize<JsonNode>(content);
-
                                     }
                                     else
                                     {
@@ -158,7 +168,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 { code=200, implicit_token = token, x_auth_token = x_auth_token, schools = schools });
+                        return Ok(new { code=200,/* implicit_token = token, schools = schools , */ x_auth_token = x_auth_token });
                     }
                     else
                     {

+ 59 - 10
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/ManageController.cs

@@ -1,4 +1,5 @@
-using IES.ExamServer.DI;
+using IES.ExamLib.Models;
+using IES.ExamServer.DI;
 using IES.ExamServer.Filters;
 using IES.ExamServer.Models;
 using Microsoft.AspNetCore.Mvc;
@@ -34,27 +35,75 @@ namespace IES.ExamServer.Controllers
         [AuthToken("admin","teacher")]
         public async Task<IActionResult> DownloadPackage(JsonNode json)
         {
-            var token = GetAuthTokenInfo();
+            
             //C#.NET 6 后端与前端流式通信
             //https://www.doubao.com/chat/collection/687687510791426?type=Thread
             //下载日志记录:1.步骤,检查,2.获取描述信息,3.分类型,4下载文件,5.前端处理,6.返回结果 , 正在下载...==> https://www.doubao.com/chat/collection/687687510791426?type=Thread  Ok...
             return Ok();
         }
         [HttpPost("search-short-code")]
-        public async Task<IActionResult> SearchShortCode(JsonNode json) 
+        public async Task<IActionResult> SearchShortCode(JsonNode json)
         {
-           
-            string shortCode = $"{json["shortCode"]}";
-            if (string.IsNullOrWhiteSpace(shortCode)) 
+            //如果要访问中心,则需要教师登录联网。  
+            var token = GetAuthTokenInfo();
+            if (token.scope.Equals(ExamConstant.ScopeTeacher))
             {
-                EvaluationClient evaluationClient =  _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x=>!string.IsNullOrWhiteSpace(x.shortCode) &&  x.shortCode.Equals(shortCode));
-                if (evaluationClient==null && _connectionService.dataCenterIsConnected) 
+                string shortCode = $"{json["shortCode"]}";
+                if (string.IsNullOrWhiteSpace(shortCode))
                 {
-                    //HttpContext.
-                 //如果要访问中心,则需要教师登录联网。  
+                    EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>()
+                        .FindOne(x => (!string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode)) || (!string.IsNullOrWhiteSpace(x.password) && x.password.Equals(shortCode)));
+                    if (evaluationClient == null && _connectionService.dataCenterIsConnected)
+                    {
+
+
+                    }
                 }
             }
+
+            return Ok();
+        }
+
+        /// <summary>
+        /// 激活考试
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [HttpPost("activate-evaluation")]
+        public IActionResult ActivateEvaluation(JsonNode json)
+        {
+            string id = $"{json["id"]}";
+            string shortCode = $"{json["shortCode"]}";
+            EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x=>x.id!.Equals(id));
+            if (evaluationClient != null) 
+            {
+            
+            }
             return Ok();
         }
+        /// <summary>
+        /// 加载本地的活动列表
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [HttpPost("list-local-evaluation")]
+        public IActionResult ListLocalEvaluation(JsonNode json) 
+        {
+            IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindAll().OrderByDescending(x=>x.activate).ThenByDescending(x=>x.stime);
+            var result = evaluationClients.Select(client =>
+            {
+                var properties = client.GetType().GetProperties();
+                var anonymousObject = new Dictionary<string, object?>();
+                foreach (var property in properties)
+                {
+                    if (!property.Name .Equals("password")  && !property.Name.Equals("shortCode"))
+                    {
+                        anonymousObject[property.Name] = property.GetValue(client);
+                    }
+                }
+                return anonymousObject;
+            });
+            return Ok(new { evaluation= result });
+        }
     }
 }

+ 16 - 7
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Filters/AuthTokenAttribute.cs

@@ -1,9 +1,11 @@
-using Microsoft.AspNetCore.Mvc;
+using IES.ExamLib.Models;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Filters;
 using Microsoft.Extensions.Primitives;
 using System.IdentityModel.Tokens.Jwt;
 using System.Security;
 using ZXing.QrCode.Internal;
+using static System.Formats.Asn1.AsnWriter;
 
 namespace IES.ExamServer.Filters
 {
@@ -27,7 +29,7 @@ namespace IES.ExamServer.Filters
             if (authTokenAttribute!=null)
             {
 
-                if (string.IsNullOrWhiteSpace(authtoken) ||  !JwtAuthExtension.ValidateAuthToken(authtoken, "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA="))
+                if (string.IsNullOrWhiteSpace(authtoken) ||  !JwtAuthExtension.ValidateAuthToken(authtoken, ExamConstant.JwtSecretKey))
                 {
                     context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult();
                 }
@@ -38,7 +40,7 @@ namespace IES.ExamServer.Filters
             else { needParse=true; }
             if (needParse)
             {
-                if (!string.IsNullOrWhiteSpace(authtoken) && JwtAuthExtension.ValidateAuthToken(authtoken, "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA="))
+                if (!string.IsNullOrWhiteSpace(authtoken) && JwtAuthExtension.ValidateAuthToken(authtoken, ExamConstant.JwtSecretKey))
                 {
                     //string msg = "";
                     //int code = 0;
@@ -50,7 +52,7 @@ namespace IES.ExamServer.Filters
                     }
                     var jwt = new JwtSecurityTokenHandler().ReadJwtToken(authtoken);
                     id = jwt.Payload.Sub;
-                    school = jwt.Payload.Azp;
+                    //school = jwt.Payload.Azp;
                     name = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("name"))?.Value;
                     picture = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("picture"))?.Value;
                     scope = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("scope"))?.Value;
@@ -76,7 +78,7 @@ namespace IES.ExamServer.Filters
                         context.HttpContext.Items.Add("ID", id);
                         context.HttpContext.Items.Add("Name", name);
                         context.HttpContext.Items.Add("Picture", picture);
-                        context.HttpContext.Items.Add("School", school);
+                        //context.HttpContext.Items.Add("School", school);
                         context.HttpContext.Items.Add("Roles", _roles);
                         context.HttpContext.Items.Add("Scope", scope);
                         context.HttpContext.Items.Add("TimeZone", TimeZone);
@@ -88,12 +90,19 @@ namespace IES.ExamServer.Filters
                 }
                 else 
                 {
-                    var _roles = new List<string> { "Guest" }; // 默认角色,访客角色
+                    var _roles = new List<string> { "visitor" }; // 默认角色,访客角色
                     context.HttpContext.Items.Add("Roles", _roles);
                     context.HttpContext.Items.Add("TimeZone", TimeZone);
+                    context.HttpContext.Items.Add("ID", $"{DateTimeOffset.Now.ToUnixTimeSeconds()}");
+                    context.HttpContext.Items.Add("Name", $"访客{Random.Shared.Next(100,999)}");
+                    context.HttpContext.Items.Add("Picture", null);
+                    context.HttpContext.Items.Add("Scope", "visitor");
                 }
             }
-             else { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); }
+            else 
+            { 
+                context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult();
+            }
              
         }
 

+ 32 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/JwtAuthExtension.cs

@@ -31,5 +31,37 @@ namespace IES.ExamServer
                 return false;
             }
         }
+
+
+        public static string CreateAuthToken(string issuer, string id, string name, string picture, string salt, string scope,   int timezone,   string schoolID =null,string[] roles = null,   int expire = 1, int year = -1)
+        {
+            // 設定要加入到 JWT Token 中的聲明資訊(Claims)  
+            var payload = new JwtPayload {
+                { JwtRegisteredClaimNames.Iss, issuer }, //發行者
+                { JwtRegisteredClaimNames.Azp,schoolID}, // 學校簡碼,如果有的話
+                { JwtRegisteredClaimNames.Sub, id }, // 用戶ID                  
+                { JwtRegisteredClaimNames.Exp,DateTimeOffset.UtcNow.AddHours(expire).ToUnixTimeSeconds()},  // 到期的時間,必須為數字
+                { "name",name}, // 用戶的顯示名稱
+                { "picture",picture}, // 用戶頭像
+                { "roles",roles}, // 登入者的角色,角色類型 (Admin、Teacher、Student) 
+                { "scope",scope},  //登入者的入口类型。 (teacher 教师端登录的醍摩豆ID、tmduser学生端登录的醍摩豆ID、student学生端登录校内账号的学生ID)
+                { "timezone",timezone},
+               
+            };
+            // 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用
+            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt));
+            // HmacSha256 有要求必須要大於 128 bits,所以 salt 不能太短,至少要 16 字元以上
+            // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
+            //var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
+            var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
+            var header = new JwtHeader(signingCredentials);
+            var secToken = new JwtSecurityToken(header, payload);
+            // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
+            var tokenHandler = new JwtSecurityTokenHandler();
+            //var securityToken = tokenHandler.CreateToken(tokenDescriptor);
+            var serializeToken = tokenHandler.WriteToken(secToken);
+
+            return serializeToken;
+        }
     }
 }

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

@@ -31,6 +31,7 @@
 	  </None>
 	</ItemGroup>
 	<ItemGroup>
+		<PackageReference Include="AutoMapper" Version="13.0.1" />
 		<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" />

+ 2 - 2
TEAMModelOS.Extension/IES.ExamLib/Models/EvaluationCommon.cs

@@ -99,7 +99,7 @@ namespace IES.ExamServer.Models
     }
 
 
-    public class EvaluationClient: EvaluationMain
+    public class EvaluationClient: EvaluationMain 
     {
         /// <summary>
         /// 开始时间
@@ -118,7 +118,7 @@ namespace IES.ExamServer.Models
         /// </summary>
         public string? recordUrl { get; set; }
         /// <summary>
-        /// 激活状态
+        /// 激活状态0未激活,1 激活
         /// </summary>
         public int activate {  get; set; }
 

+ 14 - 0
TEAMModelOS.Extension/IES.ExamLib/Models/ExamConstant.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IES.ExamLib.Models
+{
+    public class ExamConstant
+    {
+        public static readonly string ScopeTeacher = "teacher";
+        public static readonly string ScopeStudent = "student";
+        public static readonly string ScopeVisitor = "visitor";
+        public static readonly string JwtSecretKey = "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=";
+    }
+}