mirror of https://gitee.com/apiumc/Gateway.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
16 KiB
C#
396 lines
16 KiB
C#
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<String, Dictionary<String, Tuple<WebAuthType, bool>>> Auths = new Dictionary<string, Dictionary<string, Tuple<WebAuthType, bool>>>();
|
|
|
|
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<string, Tuple<WebAuthType, bool>>();
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|