|
@@ -0,0 +1,253 @@
|
|
|
+using Microsoft.AspNetCore.Mvc;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using TEAMModelOS.Models;
|
|
|
+using TEAMModelOS.SDK.DI;
|
|
|
+using System.Text.Json;
|
|
|
+using TEAMModelOS.SDK.Models;
|
|
|
+using Microsoft.AspNetCore.Http;
|
|
|
+using TEAMModelOS.SDK.Extension;
|
|
|
+using Azure.Cosmos;
|
|
|
+using System.Text;
|
|
|
+using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
|
|
|
+using Microsoft.Extensions.Options;
|
|
|
+using Azure.Messaging.ServiceBus;
|
|
|
+using Microsoft.Extensions.Configuration;
|
|
|
+using TEAMModelOS.Services.Common;
|
|
|
+using HTEXLib.COMM.Helpers;
|
|
|
+using TEAMModelOS.SDK;
|
|
|
+using System.IdentityModel.Tokens.Jwt;
|
|
|
+using TEAMModelOS.Services;
|
|
|
+using TEAMModelOS.SDK.Models.Service;
|
|
|
+using System.IO;
|
|
|
+using System.Dynamic;
|
|
|
+using Microsoft.AspNetCore.Authorization;
|
|
|
+using Azure.Storage.Blobs.Models;
|
|
|
+
|
|
|
+namespace TEAMModelOS.Controllers.Third
|
|
|
+{
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ ///
|
|
|
+ [ProducesResponseType(StatusCodes.Status200OK)]
|
|
|
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
|
+ //[Authorize(Roles = "IES5")]
|
|
|
+ [Route("sc")]
|
|
|
+ //[Route("api/[controller]")]
|
|
|
+ [ApiController]
|
|
|
+ public class ScController : ControllerBase
|
|
|
+ {
|
|
|
+ private readonly SnowflakeId _snowflakeId;
|
|
|
+ private readonly AzureCosmosFactory _azureCosmos;
|
|
|
+ private readonly DingDing _dingDing;
|
|
|
+ private readonly Option _option;
|
|
|
+ private readonly AzureStorageFactory _azureStorage;
|
|
|
+ private readonly AzureServiceBusFactory _serviceBus;
|
|
|
+ private readonly AzureRedisFactory _azureRedis;
|
|
|
+ private readonly CoreAPIHttpService _accountHttpService;
|
|
|
+ public readonly string type = "scsyxpt";
|
|
|
+ public IConfiguration _configuration { get; set; }
|
|
|
+ public ScController(AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage,
|
|
|
+ AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IConfiguration configuration, CoreAPIHttpService accountHttpService)
|
|
|
+ {
|
|
|
+ _azureCosmos = azureCosmos;
|
|
|
+ _snowflakeId = snowflakeId;
|
|
|
+ _dingDing = dingDing;
|
|
|
+ _option = option?.Value;
|
|
|
+ _azureStorage = azureStorage;
|
|
|
+ _serviceBus = serviceBus;
|
|
|
+ _configuration = configuration;
|
|
|
+ _azureRedis = azureRedis;
|
|
|
+ _accountHttpService = accountHttpService;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [ProducesDefaultResponseType]
|
|
|
+ [HttpPost("bind")]
|
|
|
+ [AllowAnonymous]
|
|
|
+ public async Task<IActionResult> Bind(SSO sso) {
|
|
|
+ var rurl = new StringBuilder($"https://{_option.HostName}/sso");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Teacher teacher = null;
|
|
|
+ if (string.IsNullOrEmpty(sso.idToken)) {
|
|
|
+ return Redirect(rurl.Append($"?status=1").ToString());
|
|
|
+ }
|
|
|
+ var jwt = new JwtSecurityToken(sso.idToken);
|
|
|
+ if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
|
|
|
+ var id = jwt.Payload.Sub;
|
|
|
+ jwt.Payload.TryGetValue("name", out object name);
|
|
|
+ jwt.Payload.TryGetValue("picture", out object picture);
|
|
|
+ var client = _azureCosmos.GetCosmosClient();
|
|
|
+ teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
|
|
|
+ //先检查绑定的平台是否已经被绑定
|
|
|
+ //四川研训平台跳转隐式登录/或者绑定IES平台接入规范
|
|
|
+ ScSSO scsso= sso.param.ToObject<ScSSO>();
|
|
|
+ string sql = $"SELECT distinct value(c) FROM c join A1 in c.binds where A1.webid='{scsso.Webid}' and A1.tid='{scsso.tid}'";
|
|
|
+ await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(queryText: sql,
|
|
|
+ requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
|
|
|
+ {
|
|
|
+ teacher = item;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (teacher != null)
|
|
|
+ {
|
|
|
+ var bind = teacher.binds.Find(x => x.source.Equals($"{scsso.Webid}") && x.userid.Equals($"{scsso.tid}"));
|
|
|
+ if (bind != null)
|
|
|
+ {
|
|
|
+ teacher.binds.Add(new Teacher.ThirdBind { pxid = new HashSet<string> { $"{scsso.Pxid}" }, userid = $"{scsso.tid}", source = $"{scsso.Webid}", type = type });
|
|
|
+ await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (bind.pxid.Add(scsso.Pxid))
|
|
|
+ {
|
|
|
+ await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ teacher = new Teacher
|
|
|
+ {
|
|
|
+ id = id,
|
|
|
+ pk = "Base",
|
|
|
+ code = "Base",
|
|
|
+ name = name?.ToString(),
|
|
|
+ picture = picture?.ToString(),
|
|
|
+ //创建账号并第一次登录IES5则默认赠送1G
|
|
|
+ size = 1,
|
|
|
+ defaultSchool = null,
|
|
|
+ schools = new List<Teacher.TeacherSchool>(),
|
|
|
+ binds= new List<Teacher.ThirdBind> { new Teacher.ThirdBind { pxid = new HashSet<string> { $"{scsso.Pxid}" }, userid = $"{scsso.tid}", source = $"{scsso.Webid}", type = type } }
|
|
|
+ };
|
|
|
+ var container = _azureStorage.GetBlobContainerClient(id);
|
|
|
+ await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
|
|
|
+ teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
|
|
|
+ }
|
|
|
+ return Ok(new
|
|
|
+ {
|
|
|
+ location = _option.Location,
|
|
|
+ status = 200,
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+
|
|
|
+ }
|
|
|
+ return Redirect(rurl.Append($"?status=1").ToString());
|
|
|
+
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+
|
|
|
+ [HttpGet("sso")]
|
|
|
+ [AllowAnonymous]
|
|
|
+ public async Task<IActionResult> Sso([FromQuery] ScSSO sso)
|
|
|
+ {
|
|
|
+ var rurl = new StringBuilder($"https://{_option.HostName}/sso");
|
|
|
+ string parmas = $"Pxid={sso.Pxid}&Webid={sso.Webid}&tid={sso.tid}&time={sso.time}";
|
|
|
+ if (Md5Hash.GetMd5String(parmas).Equals($"{sso.Encrypt}"))
|
|
|
+ {
|
|
|
+ //四川研训平台跳转隐式登录/或者绑定IES平台接入规范
|
|
|
+
|
|
|
+ long ssotime = long.Parse($"{sso.time}");
|
|
|
+ long nowtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
|
+ if (nowtime - ssotime > 60 * 10)//10分钟有效期
|
|
|
+ {
|
|
|
+ // return Ok(new { status = 2, msg = "登录超时!" });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Redirect(rurl.Append($"?status=1").ToString());
|
|
|
+ }
|
|
|
+ Teacher teacher = null;
|
|
|
+ //四川研训平台跳转隐式登录/或者绑定IES平台接入规范
|
|
|
+ //string sql = $"SELECT distinct value(c) FROM c join A1 in c.binds where A1.pxid='{sso.Pxid}' and A1.webid='{sso.Webid}' and A1.tid='{sso.tid}'";
|
|
|
+ string sql = $"SELECT distinct value(c) FROM c join A1 in c.binds where A1.source='{sso.Webid}' and A1.userid='{sso.tid}'";
|
|
|
+ await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(queryText: sql,
|
|
|
+ requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
|
|
|
+ {
|
|
|
+ teacher = item;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (teacher == null)
|
|
|
+ {
|
|
|
+ return Redirect(rurl.Append($"?status=0¶m={sso.ToJsonString()}&type={type}&bindurl=sc/bind").ToString());
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
|
|
|
+ var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
|
|
|
+ var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
|
|
|
+ var location = _option.Location;
|
|
|
+ (int code, string content) = await _accountHttpService.Implicit(clientID, clientSecret, location, $"{url}/oauth2/implicit",
|
|
|
+ new Dictionary<string, string>()
|
|
|
+ {
|
|
|
+ { "grant_type", "implicit" },
|
|
|
+ { "client_id",clientID },
|
|
|
+ { "account",teacher.id },
|
|
|
+ { "nonce",Guid.NewGuid().ToString()}
|
|
|
+ });
|
|
|
+ TmdidImplicit implicit_token = new TmdidImplicit();
|
|
|
+ if (!string.IsNullOrEmpty(content) && code==200)
|
|
|
+ {
|
|
|
+ implicit_token = content.ToObject<TmdidImplicit>();
|
|
|
+ var bind = teacher.binds.Find(x => x.userid.Equals(sso.tid) && x.source.Equals(sso.Webid));
|
|
|
+ if (bind != null) {
|
|
|
+ if (bind.pxid != null)
|
|
|
+ {
|
|
|
+ if (bind.pxid.Add(sso.Pxid))
|
|
|
+ {
|
|
|
+ await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ bind.pxid = new HashSet<string> { sso.Pxid };
|
|
|
+ await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Redirect(rurl.Append($"?status=200&id_token={implicit_token.id_token}&access_token={implicit_token.access_token}&expires_in={implicit_token.expires_in}&token_type={implicit_token.token_type}").ToString());
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //绑定失效
|
|
|
+ if (teacher.binds.IsNotEmpty()) {
|
|
|
+ teacher.binds.RemoveAll(x => x.userid.Equals(sso.tid) && x.source.Equals(sso.Webid));
|
|
|
+ await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher,teacher.id,new PartitionKey(teacher.code));
|
|
|
+ }
|
|
|
+ return Redirect(rurl.Append($"?status=0¶m={sso.ToJsonString()}&type={type}&bindurl=sc/bind").ToString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public record ScSSO{
|
|
|
+ public string Webid { get; set; }
|
|
|
+ public string Pxid { get; set; }
|
|
|
+ public string tid { get; set; }
|
|
|
+ public string time { get; set; }
|
|
|
+ public string Encrypt { get; set; }
|
|
|
+ public string idToken { get; set; }
|
|
|
+ }
|
|
|
+ public record SSO
|
|
|
+ {
|
|
|
+ public string type { get; set; }
|
|
|
+ public string param { get; set; }
|
|
|
+ public string idToken { get; set; }
|
|
|
+ }
|
|
|
+ public record TmdidImplicit {
|
|
|
+ public string id_token { get; set; }
|
|
|
+ public string access_token { get; set; }
|
|
|
+ public string expires_in { get; set; }
|
|
|
+ public string token_type { get; set; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|