using System; using System.Collections.Generic; using System.Text; using System.Linq; using UMC.Data; using UMC.Net; using UMC.Web; using UMC.Security; using UMC.ITME.Entities; using System.Collections; // using System.Net; namespace UMC.ITME { [Apiumc(Weight = 0, Desc = "云模块服务组件")] public class WebFactory : IWebFactory { class XHRException : Exception { String _t; public XHRException(String xhr) { _t = xhr; } public override string ToString() { return _t; } } internal static Dictionary>> Auths = new Dictionary>>(); class XHRActivity : WebActivity { public XHRActivity(SiteConfig site) { this.site = site; } SiteConfig site; public override void ProcessActivity(WebRequest request, WebResponse response) { var user = this.Context.Token.Identity(); var httpProxy = new HttpProxy(site, this.Context.Client.Context, -1, "/", String.Empty); if (httpProxy.Domain == null) { this.Prompt("安全审记", $"此应用临时关闭,请联系应用管理员"); } switch (site.Site.UserModel) { case UserModel.Bridge: break; default: this.Prompt("UMC云模块只支持权限桥接模式"); break; } if (Auths.TryGetValue(site.Root, out var _dic) == false) { _dic = new Dictionary>(); new Uri(httpProxy.Domain, "/UMC/System/Setup/Mapping").WebRequest().Get(r => { r.ReadAsString(js => { var ds = JSON.Deserialize(js) as Hashtable; if (ds?.ContainsKey("data") == true) { var data = ds["data"] as Array; foreach (var o in data) { var dic = o as Hashtable; if (dic.ContainsKey("model")) { var model = dic["model"] as string; var auth = dic["auth"] as string; WebAuthType authType = WebAuthType.All; switch (auth) { case "all": continue; case "admin": authType = WebAuthType.Admin; break; case "guest": authType = WebAuthType.Guest; break; case "user": authType = WebAuthType.User; break; case "usercheck": authType = WebAuthType.UserCheck; break; case "check": authType = WebAuthType.Check; break; } if (dic.ContainsKey("cmd")) { _dic[$"{model}.{dic["cmd"]}"] = Tuple.Create(authType, dic.ContainsKey("biometric")); } else { _dic[model] = Tuple.Create(authType, dic.ContainsKey("biometric")); } } } Auths[site.Root] = _dic; } }, e => { }); }); } if (this.Context.Items.Contains(typeof(WebFactory)) == false) { bool isBiometric; if (site.Site.IsAuth == true) { if (WebClient.Verify(httpProxy.Account, site.Site.SiteKey.Value, request.Model, request.Command, _dic, out isBiometric) == false) { if (user.IsAuthenticated) { this.Prompt("访问受限,请联系管理员"); } else { this.Context.Send("Login", true); } } } else { if (WebClient.Verify(user, 0, request.Model, request.Command, _dic, out isBiometric) == false) { if (user.IsAuthenticated) { this.Prompt("访问受限,请联系管理员"); } else { this.Context.Send("Login", true); } } } if (isBiometric && this.Context.Token.BiometricTime == 0) { var send = request.SendValues ?? new WebMeta(); var vs = request.Headers.GetDictionary()[request.Command]; if (vs is string) { send.Put("_", vs); } else if (vs is string[]) { var stv = vs as string[]; if (stv.Length > 0) { send.Put("__", String.Join('/', stv)); } } if (send.Count > 0) { response.Redirect("Account", "Biometric", new WebMeta().Put("oauth_callback", $"/UMC/{request.Model}{request.Command}?{UMC.Data.JSON.Serialize(send)}"), true); } else { response.Redirect("Account", "Biometric", new WebMeta().Put("oauth_callback", $"/UMC/{request.Model}{request.Command}"), true); } } this.Context.Items[typeof(WebFactory)] = true; } StringBuilder sb = new StringBuilder(); sb.Append("_model="); sb.Append(request.Model); sb.Append("&_cmd="); sb.Append(request.Command); var sv = request.SendValues; if (sv != null) { var em = sv.GetDictionary().GetEnumerator(); while (em.MoveNext()) { sb.Append("&"); sb.Append(Uri.EscapeDataString(em.Key.ToString())); sb.Append("="); sb.Append(Uri.EscapeDataString(em.Value.ToString())); } } var values = request.Headers.GetDictionary()[request.Command]; if (values is string) { sb.Append("&_="); sb.Append(Uri.EscapeDataString(values as string)); } else if (values is string[]) { var stv = values as string[]; if (stv.Length > 0) { sb.Append("&__="); sb.Append(Uri.EscapeDataString(String.Join('/', stv))); } } var query = request.Url.Query ?? ""; if (query.StartsWith("?_v=")) { int v = query.IndexOf('&'); if (v > 0) { query = query.Substring(0, v); } } var content = this.Context.Client.Context; var webReq = httpProxy.Reqesut(content.Transfer(httpProxy.Domain)); httpProxy.AuthBridge(webReq.Headers); // webReq.Headers[] webReq.Headers["x-forwarded-proto"] = request.Url.Scheme; webReq.Headers[System.Net.HttpRequestHeader.Host] = request.Url.Authority; webReq.RawUrl = $"/UMC/{Utility.Guid(this.Context.Token.Device.Value)}/{query}"; webReq.ContentType = "application/x-www-form-urlencoded"; webReq.Post(sb.ToString(), res => { var token = res.Headers.Get("itme-access-token"); if (String.IsNullOrEmpty(token) == false) { if (String.Equals(httpProxy.SiteCookie.Cookies, token) == false) { httpProxy.SiteCookie.Cookies = token; httpProxy.IsChangeUser = true; httpProxy.SaveCookie(); } } int StatusCode = (int)res.StatusCode; HttpProxy.LogWrite(httpProxy.Context, httpProxy.Site, StatusCode, webReq.RawUrl, httpProxy.SiteCookie.Account, null, String.Empty); if (StatusCode > 300 && StatusCode < 400) { var url = res.Headers.Get("Location"); response.Headers.Put("Data", new Uri(content.Url, url)); response.ClientEvent |= (WebEvent)131072; this.Context.OutputFinish(); } else if (StatusCode == 200) { res.ReadAsString(xhr => { if (xhr.StartsWith("{\"ClientEvent\":")) { var xData = JSON.Deserialize(xhr) as Hashtable; var webEvent = (WebEvent)Utility.Parse(xData["ClientEvent"].ToString(), 0); response.ClientEvent = webEvent; if (xData.ContainsKey("Headers")) { var header = xData["Headers"] as Hashtable; var m = header.GetEnumerator(); while (m.MoveNext()) { response.Headers.Put(m.Key as string, m.Value); } } if (xData.ContainsKey("Redirect")) { var redirect = xData["Redirect"] as Hashtable; var model = redirect["model"] as string; var cmd = redirect["cmd"] as string; if (String.IsNullOrEmpty(model) == false && String.IsNullOrEmpty(cmd) == false) { this.Context.Items[$"XHR.{model}.{cmd}"] = site.Root; var send = redirect["send"]; if (send is IDictionary) { response.Redirect(model, cmd, new WebMeta(send as IDictionary), false); } else if (send is string) { response.Redirect(model, cmd, send as string, false); } else { response.Redirect(model, cmd, false); } } } } else { response.Headers.Put("Data", Data.JSON.Expression(xhr)); response.ClientEvent |= (WebEvent)131072; } this.Context.OutputFinish(); }, error => { if (error is WebAbortException) { this.Context.OutputFinish(); } else { this.Context.Client.Context.Error(error); } }); } else { // httpProxy.ProcessEnd(); if (res.Error != null) { this.Prompt(site.Site.Caption, $"异常:{res.Error.Message}.", false); this.Context.OutputFinish(); } else { res.Transfer(this.Context.Client.Context); } } }); response.Redirect(Empty); } } class XHRFlow : WebFlow { public override WebActivity GetFirstActivity() { var m = this.Context.Request.Model; var cmd = this.Context.Request.Command; var cgf = Data.Reflection.Configuration("UMC"); var p = cgf[$"{m}.{cmd}"] ?? cgf[$"{m}.*"]; if (p != null) { var root = p.Attributes["root"]; var lold = this.Context.Items[$"XHR.{m}.{cmd}"] as string; if (String.IsNullOrEmpty(root) == false && String.Equals(lold, root) == false) { var site = DataFactory.Instance().SiteConfig(p.Attributes["root"]); if (site != null) { if (site.IsClose) { if (site.Site.Flag < 0 || site.Domains.Length == 0 || String.IsNullOrEmpty(site.Site.MarketKey)) { return WebActivity.Empty; } else { this.Prompt("许可证已过期", $"{site.Site}的许可证已经过期,请联系管理员更新许可证"); } } return new XHRActivity(site); } } } return WebActivity.Empty; } } void IWebFactory.OnInit(WebContext context) { } WebFlow IWebFactory.GetFlow(WebContext context, string mode) { return new XHRFlow(); } } }