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.
Gateway/Proxy/WebFactory.cs

302 lines
12 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.Proxy.Entities;
using System.Collections;
namespace UMC.Proxy
{
[Mapping(Weight = 0, Desc = "云模块服务组件")]
public class WebFactory : IWebFactory
{
internal static Dictionary<String, Dictionary<String, WebAuthType>> Auths = new Dictionary<string, Dictionary<string, WebAuthType>>();
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, WebAuthType>();
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"]}"] = authType;
}
else
{
_dic[model] = authType;
}
}
}
Auths[site.Root] = _dic;
}
}, e => { });
});
}
if (this.Context.Items.Contains(typeof(WebFactory)) == false)
{
if (site.Site.IsAuth == true)
{
if (WebClient.Verify(httpProxy.Account, site.Site.SiteKey.Value, request.Model, request.Command, _dic) == false)
{
if (!user.IsAuthenticated)
this.Context.Send("Login", false);
this.Prompt("访问此云模块受限");
}
}
else
{
if (WebClient.Verify(user, 0, request.Model, request.Command, _dic) == false)
{
if (!user.IsAuthenticated)
this.Context.Send("Login", false);
this.Prompt("访问此云模块受限");
}
}
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)));
}
}
httpProxy.AuthBridge();
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));
webReq.RawUrl = $"/UMC/{Utility.Guid(this.Context.Token.Device.Value)}/{query}";
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.Post(sb.ToString(), res =>
{
int StatusCode = (int)res.StatusCode;
if (StatusCode > 300 && StatusCode < 400)
{
httpProxy.ProcessEnd();
var url = res.Headers.Get("Location");
response.Redirect(new Uri(content.Url, url));
this.Context.OutputFinish();
}
else
{
res.ReadAsString(xhr =>
{
httpProxy.ProcessEnd();
String eventPfx = "{\"ClientEvent\":";
if (xhr.StartsWith(eventPfx))
{
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)
{
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);
}
});
}
});
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"];
if (String.IsNullOrEmpty(root) == false)
{
var site = DataFactory.Instance().SiteConfig(p.Attributes["root"]);
if (site != null)
return new XHRActivity(site);
}
}
return WebActivity.Empty;
}
}
public virtual WebFlow GetFlowHandler(string mode)
{
return new XHRFlow();
}
/// <summary>
/// 请在此方法中完成url与model的注册,即调用registerModel方法
/// </summary>
/// <param name="context"></param>
public virtual void OnInit(WebContext context)
{
}
}
}