Browse Source

新增同意或申請加入學校API,調整AuthToken屬性

JAELYS 4 years ago
parent
commit
ca50825962

+ 3 - 3
TEAMModelOS.SDK/Extension/HttpContextExtensions.cs

@@ -65,13 +65,13 @@ namespace TEAMModelOS.SDK.Extension
         /// </summary>        
         /// </summary>        
         /// <param name="key">Key Name</param>
         /// <param name="key">Key Name</param>
         /// <returns></returns>
         /// <returns></returns>
-        public static (string id,string school) GetAuthTokenInfo(this HttpContext httpContext, string key = null)
+        public static (string id,string name,string picture,string school) GetAuthTokenInfo(this HttpContext httpContext, string key = null)
         {            
         {            
-                object id= null, school = null;
+                object id= null,name=null, picture=null, school = null;
                 httpContext?.Items.TryGetValue("ID", out id);
                 httpContext?.Items.TryGetValue("ID", out id);
                 httpContext?.Items.TryGetValue("School", out school);
                 httpContext?.Items.TryGetValue("School", out school);
 
 
-                return (id?.ToString(), school?.ToString());          
+                return (id?.ToString(), name?.ToString(), picture?.ToString(), school?.ToString());          
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 4 - 2
TEAMModelOS.SDK/Extension/JwtAuthExtension.cs

@@ -15,13 +15,15 @@ namespace TEAMModelOS.SDK.Extension
 {
 {
     public static class JwtAuthExtension
     public static class JwtAuthExtension
     {
     {
-        public static string CreateAuthToken(string issuer, string userID, string salt, string schoolID = "", string[] roles = null, string[] permissions = null, int expire = 1)
+        public static string CreateAuthToken(string issuer, string id,string name,string picture, string salt, string schoolID = "", string[] roles = null, string[] permissions = null, int expire = 1)
         {
         {
             // 設定要加入到 JWT Token 中的聲明資訊(Claims)
             // 設定要加入到 JWT Token 中的聲明資訊(Claims)
             var claims = new List<Claim>();
             var claims = new List<Claim>();
             // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims
             // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims
             claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); //發行者
             claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); //發行者
-            claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userID)); // 用戶ID   
+            claims.Add(new Claim(JwtRegisteredClaimNames.Sub, id)); // 用戶ID  
+            claims.Add(new Claim("name", name)); // 用戶的顯示名稱
+            claims.Add(new Claim("picture", picture)); // 用戶頭像
             claims.Add(new Claim(JwtRegisteredClaimNames.Azp, schoolID)); // 學校簡碼,如果有的話
             claims.Add(new Claim(JwtRegisteredClaimNames.Azp, schoolID)); // 學校簡碼,如果有的話
             claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddHours(expire).ToUnixTimeSeconds().ToString())); // 到期的時間,必須為數字
             claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddHours(expire).ToUnixTimeSeconds().ToString())); // 到期的時間,必須為數字
 
 

+ 1 - 2
TEAMModelOS.SDK/Extension/Utils.cs

@@ -84,8 +84,7 @@ namespace TEAMModelOS.SDK.Extension
                 d.Add(item.Substring(0, a), item.Substring(a + 1));
                 d.Add(item.Substring(0, a), item.Substring(a + 1));
             }
             }
             return d;
             return d;
-        }
-        
+        }    
 
 
         private static int SetRandomSeeds(int length)
         private static int SetRandomSeeds(int length)
         {
         {

+ 3 - 2
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -60,6 +60,8 @@ namespace TEAMModelOS.Controllers.Client
                 var jwt = new JwtSecurityToken(id_token.GetString());
                 var jwt = new JwtSecurityToken(id_token.GetString());
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
                 var id = jwt.Payload.Sub;
                 var id = jwt.Payload.Sub;
+                jwt.Payload.TryGetValue("name", out object name);
+                jwt.Payload.TryGetValue("picture", out object picture);
 
 
                 object schools = null;
                 object schools = null;
                 //TODK 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
                 //TODK 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
@@ -77,8 +79,7 @@ namespace TEAMModelOS.Controllers.Client
                 else
                 else
                 {
                 {
                     //如果沒有,則初始化Teacher基本資料到Cosmos
                     //如果沒有,則初始化Teacher基本資料到Cosmos
-                    jwt.Payload.TryGetValue("name", out object name);
-                    jwt.Payload.TryGetValue("picture", out object picture);
+                   
                     using var stream = new MemoryStream();
                     using var stream = new MemoryStream();
                     using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
                     using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
                     writer.WriteStartObject();
                     writer.WriteStartObject();

+ 54 - 11
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -45,7 +45,7 @@ namespace TEAMModelOS.Controllers
         private readonly DingDing _dingDing;
         private readonly DingDing _dingDing;
         private readonly Option _option;
         private readonly Option _option;
 
 
-        public InitController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage,DingDing dingDing,IOptionsSnapshot<Option> option)
+        public InitController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option)
         {
         {
             _azureCosmos = azureCosmos;
             _azureCosmos = azureCosmos;
             _azureStorage = azureStorage;
             _azureStorage = azureStorage;
@@ -56,7 +56,7 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
         //[AuthToken(Roles = "Teacher")]
         //[AuthToken(Roles = "Teacher")]
         [HttpPost("get-teacher-info")]
         [HttpPost("get-teacher-info")]
-        
+
         public async Task<IActionResult> GetTeacherInfo(JsonElement request)
         public async Task<IActionResult> GetTeacherInfo(JsonElement request)
         {
         {
             //Debug
             //Debug
@@ -65,8 +65,11 @@ namespace TEAMModelOS.Controllers
             {
             {
                 if (!request.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
                 if (!request.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
                 var jwt = new JwtSecurityToken(id_token.GetString());
                 var jwt = new JwtSecurityToken(id_token.GetString());
+                //TODO 此驗證IdToken先簡單檢查,後面需向Core ID新API,驗證Token
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
                 var id = jwt.Payload.Sub;
                 var id = jwt.Payload.Sub;
+                jwt.Payload.TryGetValue("name", out object name);
+                jwt.Payload.TryGetValue("picture", out object picture);
 
 
                 object schools = null;
                 object schools = null;
                 string defaultschool = null;
                 string defaultschool = null;
@@ -91,8 +94,7 @@ namespace TEAMModelOS.Controllers
                 else
                 else
                 {
                 {
                     //如果沒有,則初始化Teacher基本資料到Cosmos
                     //如果沒有,則初始化Teacher基本資料到Cosmos
-                    jwt.Payload.TryGetValue("name", out object name);
-                    jwt.Payload.TryGetValue("picture", out object picture);
+
                     using var stream = new MemoryStream();
                     using var stream = new MemoryStream();
                     using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
                     using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
                     writer.WriteStartObject();
                     writer.WriteStartObject();
@@ -108,7 +110,7 @@ namespace TEAMModelOS.Controllers
                     //Debug
                     //Debug
                     //string teacher = Encoding.UTF8.GetString(stream.ToArray());
                     //string teacher = Encoding.UTF8.GetString(stream.ToArray());
                     response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOSTemp", "Teacher").CreateItemStreamAsync(stream, new PartitionKey("Base"));
                     response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOSTemp", "Teacher").CreateItemStreamAsync(stream, new PartitionKey("Base"));
-                }            
+                }
 
 
                 //私人課程
                 //私人課程
                 List<object> courses = new List<object>();
                 List<object> courses = new List<object>();
@@ -138,13 +140,14 @@ namespace TEAMModelOS.Controllers
                     }
                     }
                 }
                 }
 
 
-                var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, _option.JwtSecretKey, roles: new[] { "Teacher" });
+                //換取AuthToken,提供給前端
+                var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name.ToString(), picture.ToString(), _option.JwtSecretKey, roles: new[] { "Teacher" });
 
 
                 //取得Teacher Blob 容器位置及SAS 
                 //取得Teacher Blob 容器位置及SAS 
                 var container = _azureStorage.GetBlobContainerClient(id);
                 var container = _azureStorage.GetBlobContainerClient(id);
                 await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
                 await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read);
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read);
-                
+
                 return Ok(new { auth_token, blob_uri, blob_sas, schools, defaultschool, courses, syllabus });
                 return Ok(new { auth_token, blob_uri, blob_sas, schools, defaultschool, courses, syllabus });
 
 
             }
             }
@@ -157,7 +160,7 @@ namespace TEAMModelOS.Controllers
 
 
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
         //[AuthToken(Roles = "Teacher")]
         //[AuthToken(Roles = "Teacher")]
-        [HttpPost("get-school-info")]        
+        [HttpPost("get-school-info")]
         public async Task<IActionResult> GetSchoolInfo(JsonElement requert)
         public async Task<IActionResult> GetSchoolInfo(JsonElement requert)
         {
         {
             //var (id, school) = HttpContext.GetAuthTokenInfo(); //此API有設置權杖,需要取得權杖使用者id及當前學校代碼(學校不一定有)
             //var (id, school) = HttpContext.GetAuthTokenInfo(); //此API有設置權杖,需要取得權杖使用者id及當前學校代碼(學校不一定有)
@@ -171,7 +174,7 @@ namespace TEAMModelOS.Controllers
             var client = _azureCosmos.GetCosmosClient();
             var client = _azureCosmos.GetCosmosClient();
             List<object> courses = new List<object>();
             List<object> courses = new List<object>();
             var query = $"select c.id,c.name,c.period,c.subject,c.notice,c.scope from c where ARRAY_CONTAINS(c.teacherIds, {id} , true)";
             var query = $"select c.id,c.name,c.period,c.subject,c.notice,c.scope from c where ARRAY_CONTAINS(c.teacherIds, {id} , true)";
-            await foreach (var item in client.GetContainer("TEAMModelOSTemp", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school_code}") }))
+            await foreach (var item in client.GetContainer("TEAMModelOSTemp", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school_code.GetString()}") }))
             {
             {
                 using var json = await JsonDocument.ParseAsync(item.ContentStream);
                 using var json = await JsonDocument.ParseAsync(item.ContentStream);
                 if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                 if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
@@ -187,7 +190,7 @@ namespace TEAMModelOS.Controllers
 
 
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
         //[AuthToken(Roles = "Teacher")]
         //[AuthToken(Roles = "Teacher")]
-        [HttpPost("get-school-list")]        
+        [HttpPost("get-school-list")]
         public async Task<IActionResult> GetSchoolList()
         public async Task<IActionResult> GetSchoolList()
         {
         {
             var client = _azureCosmos.GetCosmosClient();
             var client = _azureCosmos.GetCosmosClient();
@@ -196,7 +199,7 @@ namespace TEAMModelOS.Controllers
             await foreach (var item in client.GetContainer("TEAMModelOSTemp", "School").GetItemQueryStreamIterator(queryText: $"select c.id, c.name,c.region,c.province,c.city from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
             await foreach (var item in client.GetContainer("TEAMModelOSTemp", "School").GetItemQueryStreamIterator(queryText: $"select c.id, c.name,c.region,c.province,c.city from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
             {
             {
                 using var json = await JsonDocument.ParseAsync(item.ContentStream);
                 using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                
+
                 if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                 if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                 {
                 {
                     foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                     foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
@@ -208,5 +211,45 @@ namespace TEAMModelOS.Controllers
 
 
             return Ok(new { schools });
             return Ok(new { schools });
         }
         }
+
+        /// <summary>
+        /// 申請或同意邀請加入學校
+        /// </summary>
+        /// <param name="requert"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [AuthToken(Roles = "Teacher")]
+        [HttpPost("join-school")]
+        public async Task<IActionResult> JoinSchool(JsonElement requert)
+        {
+            if (!requert.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
+            if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
+            var (id, name, picture, _) = HttpContext.GetAuthTokenInfo();
+
+            var client = _azureCosmos.GetCosmosClient();
+
+            //在學校表加入老師
+            using var stream = new MemoryStream();
+            using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
+            writer.WriteStartObject();
+            writer.WriteString("pk", $"Teacher");
+            writer.WriteString("code", $"Teacher-{school_code}");
+            writer.WriteString("id", id);
+            writer.WriteString("name", name);
+            writer.WriteString("picture", picture);
+            writer.WriteString("status", grant_type.GetString()); //處理同意join or 申請request
+            writer.WriteString("job", picture);
+            writer.WriteNumber("createDate", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
+            writer.WriteStartArray("roles");
+            writer.WriteEndArray();
+            writer.WriteStartArray("permissions");
+            writer.WriteEndArray();
+            writer.WriteEndObject();
+            writer.Flush();
+            var response = await client.GetContainer("TEAMModelOSTemp", "School").CreateItemStreamAsync(stream, new PartitionKey($"Teacher-{school_code}"));
+
+            return Ok();
+        }
+
     }
     }
 }
 }

+ 6 - 1
TEAMModelOS/Filter/AuthTokenAttribute.cs

@@ -37,13 +37,16 @@ namespace TEAMModelOS.Filter
             public void OnResourceExecuting(ResourceExecutingContext context)
             public void OnResourceExecuting(ResourceExecutingContext context)
             {
             {
                 bool pass = false;
                 bool pass = false;
-                string id = string.Empty, school = string.Empty;
+                string id = string.Empty, name = string.Empty, picture = string.Empty, school = string.Empty;
                 var authtoken = context.HttpContext.GetXAuth("AuthToken");
                 var authtoken = context.HttpContext.GetXAuth("AuthToken");
                 if (!string.IsNullOrWhiteSpace(authtoken) && JwtAuthExtension.ValidateAuthToken(authtoken, _option.JwtSecretKey))
                 if (!string.IsNullOrWhiteSpace(authtoken) && JwtAuthExtension.ValidateAuthToken(authtoken, _option.JwtSecretKey))
                 {
                 {
                     var jwt = new JwtSecurityTokenHandler().ReadJwtToken(authtoken);
                     var jwt = new JwtSecurityTokenHandler().ReadJwtToken(authtoken);
                     id = jwt.Payload.Sub;
                     id = jwt.Payload.Sub;
                     school = jwt.Payload.Azp;
                     school = jwt.Payload.Azp;
+                    name = jwt.Claims.First(claim => claim.Type == "name").Value;
+                    picture = jwt.Claims.First(claim => claim.Type == "picture").Value;
+
                     if (!string.IsNullOrWhiteSpace(_roles))
                     if (!string.IsNullOrWhiteSpace(_roles))
                     {
                     {
                         var roles = jwt.Claims.Where(c => c.Type == "roles");
                         var roles = jwt.Claims.Where(c => c.Type == "roles");
@@ -73,6 +76,8 @@ namespace TEAMModelOS.Filter
                 if (pass)
                 if (pass)
                 {
                 {
                     context.HttpContext.Items.Add("ID", id);
                     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);
                 }
                 }
                 else
                 else