From feb517dd8da9c2a51caabf8e23463dc43e773240 Mon Sep 17 00:00:00 2001 From: geh <1923421292@qq.com> Date: Thu, 13 Nov 2025 17:32:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=90=E5=85=AC=E5=8F=B8=E9=9B=86=E6=88=90?= =?UTF-8?q?=E9=9B=86=E5=9B=A2=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUBQHSE/BLL/BLL.csproj | 1 + SUBQHSE/BLL/TokenHelper.cs | 127 +++++++++++++++++++++++ SUBQHSE/FineUIPro.Web/common/PageBase.cs | 94 +++++++++++++---- 3 files changed, 200 insertions(+), 22 deletions(-) create mode 100644 SUBQHSE/BLL/TokenHelper.cs diff --git a/SUBQHSE/BLL/BLL.csproj b/SUBQHSE/BLL/BLL.csproj index e3ca3e0..33a221d 100644 --- a/SUBQHSE/BLL/BLL.csproj +++ b/SUBQHSE/BLL/BLL.csproj @@ -895,6 +895,7 @@ + diff --git a/SUBQHSE/BLL/TokenHelper.cs b/SUBQHSE/BLL/TokenHelper.cs new file mode 100644 index 0000000..9ce6b09 --- /dev/null +++ b/SUBQHSE/BLL/TokenHelper.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Newtonsoft.Json; + +namespace BLL +{ + /// + /// Token加密解密工具类 + /// 用于iframe跨域自动登录的token处理 + /// + public static class TokenHelper + { + // 默认密钥,建议从配置文件中读取 + private static readonly string SecretKey = "cncec-subqhse-256bit-secret-key-for-auth-token"; + + /// + /// 加密Token + /// + /// 明文 + /// 加密后的Base64字符串 + public static string EncryptToken(string plainText) + { + try + { + // 确保密钥长度为32字节(256位) + string key = SecretKey.PadRight(32, '0').Substring(0, 32); + + using (var aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = new byte[16]; // 使用固定IV,简化实现 + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using (var encryptor = aes.CreateEncryptor()) + using (var msEncrypt = new MemoryStream()) + { + using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) + using (var swEncrypt = new StreamWriter(csEncrypt)) + { + swEncrypt.Write(plainText); + } + return Convert.ToBase64String(msEncrypt.ToArray()); + } + } + } + catch (Exception ex) + { + throw new Exception($"Token加密失败: {ex.Message}", ex); + } + } + + /// + /// 解密Token + /// + /// 加密的Base64字符串 + /// 解密后的明文 + public static string DecryptToken(string cipherText) + { + try + { + // 确保密钥长度为32字节(256位) + string key = SecretKey.PadRight(32, '0').Substring(0, 32); + + using (var aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = new byte[16]; // 使用固定IV,与加密一致 + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using (var decryptor = aes.CreateDecryptor()) + using (var msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText))) + using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + using (var srDecrypt = new StreamReader(csDecrypt)) + { + return srDecrypt.ReadToEnd(); + } + } + } + catch (Exception ex) + { + throw new Exception($"Token解密失败: {ex.Message}", ex); + } + } + + /// + /// 生成认证Token + /// + /// 用户ID + /// 来源标识 + /// 加密的Token + public static string GenerateAuthToken(string userId, string source = "qhse.cncecoa.com") + { + var tokenData = new + { + user_id = userId, + timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(), + source = source, + random = Guid.NewGuid().ToString("N").Substring(0, 8) // 添加8位随机数增强安全性 + }; + + string json = JsonConvert.SerializeObject(tokenData); + return EncryptToken(json); + } + + /// + /// 验证Token格式 + /// + /// Token字符串 + /// 是否为有效的Base64格式 + public static bool IsValidTokenFormat(string token) + { + try + { + Convert.FromBase64String(token); + return true; + } + catch + { + return false; + } + } + } +} \ No newline at end of file diff --git a/SUBQHSE/FineUIPro.Web/common/PageBase.cs b/SUBQHSE/FineUIPro.Web/common/PageBase.cs index 0e1c492..0bb9fe5 100644 --- a/SUBQHSE/FineUIPro.Web/common/PageBase.cs +++ b/SUBQHSE/FineUIPro.Web/common/PageBase.cs @@ -131,37 +131,87 @@ namespace FineUIPro.Web protected override void OnInit(EventArgs e) { - string url = HttpContext.Current.Request.Path; - - string a = Request.ServerVariables["HTTP_REFERER"]; - string Referer = Request.Headers["Referer"]; - if (a==null) + string fullPath = HttpContext.Current.Request.Path; + string appPath = HttpContext.Current.Request.ApplicationPath; // 获取应用程序根路径 + // 确保应用程序路径以 "/" 开头并移除它 + if (!string.IsNullOrEmpty(appPath) && fullPath.StartsWith(appPath, StringComparison.OrdinalIgnoreCase)) { - bool IsDataShowPage = ConstValue.drpConstItemList(ConstValue.Group_InterfacePopup).FirstOrDefault(x => url.Contains(x.ConstValue)) != null; - bool IsSafeReferer = ConstValue.drpConstItemList(ConstValue.Group_SafeReferer).FirstOrDefault(x => x.ConstValue == url) != null; - - if (!IsDataShowPage && !IsSafeReferer) - { - if (this.Page.Request.AppRelativeCurrentExecutionFilePath != "~/Login.aspx") - Response.Redirect("~/Login.aspx"); - return; - } - + fullPath = fullPath.Substring(appPath.Length); // 去掉应用程序根路径 } - else + //去除fullPath 开头的 / + if (fullPath.StartsWith("/")) { - Uri uri = new Uri(a); - Uri uri2 = new Uri(SysConstSetService.CNCECPath); - if (uri.Host==uri2.Host) + fullPath = fullPath.Remove(0, 1); + } + // 检查auth_token参数实现iframe自动登录 + string authToken = Request.QueryString["auth_token"]; + if (!string.IsNullOrEmpty(authToken) && this.CurrUser == null) + { + try { - if (this.CurrUser == null) + // 解密并验证token + string decryptedToken = BLL.TokenHelper.DecryptToken(authToken); + var tokenData = JsonConvert.DeserializeObject(decryptedToken); + + // 验证时间戳(2小时有效期) + long timestamp = tokenData.timestamp; + if (DateTimeOffset.Now.ToUnixTimeSeconds() - timestamp <= 7200) // 2小时 = 7200秒 { - this.Session["CurrUser"] = UserService.GetUserByUserId(Const.sysglyId); + // 验证用户ID + string userId = tokenData.user_id; + if (userId == Const.sysglyId) + { + var user = UserService.GetUserByUserId(Const.sysglyId); + if (user != null) + { + this.Session["CurrUser"] = user; + BLL.LogService.AddLog(Const.sysglyId, "iframe Token自动登录成功"); + } + } + } + } + catch (Exception ex) + { + BLL.LogService.AddLog("", $"iframe Token自动登录失败:{ex.Message}"); + } + } + string httpRefere = Request.ServerVariables["HTTP_REFERER"]; + if (httpRefere==null) //判断是否为空。目的是为了防止直接在浏览器地址栏输入网址访问 + { + bool IsDataShowPage = ConstValue.drpConstItemList(ConstValue.Group_InterfacePopup).FirstOrDefault(x => fullPath.Contains(x.ConstValue)) != null; + bool IsSafeReferer = ConstValue.drpConstItemList(ConstValue.Group_SafeReferer).FirstOrDefault(x => x.ConstValue == fullPath) != null; + + // 如果不在安全页面列表中且用户未登录,重定向到登录页面 + if (!IsDataShowPage && !IsSafeReferer && this.CurrUser == null) + { + string loginform = ConfigurationManager.AppSettings["LoginForm"]; + if (!string.IsNullOrEmpty(loginform)) + { + if (this.Page.Request.AppRelativeCurrentExecutionFilePath != "~/Login_ZJ.aspx") + Response.Redirect("~/Login_ZJ.aspx"); + return; } } } + /*if (CurrUser == null && HttpContext.Current.Request.Path != FormsAuthentication.LoginUrl)//防止没有登录直接访问通用界面 + { + Response.Redirect(FormsAuthentication.LoginUrl); + + }*/ + //var menuModel = (from x in Funs.DB.Sys_Menu where x.Url.Contains(fullPath) select x.MenuId).ToList();//判断访问的页面是否在菜单中 + //if (menuModel!=null&&menuModel.Count>0) + //{ + // var thisUserAllMenuIdLis = CommonService.GetAllMenuList(this.CurrUser.LoginProjectId, this.CurrUser.UserId); + // if (menuModel.Intersect(thisUserAllMenuIdLis).Count()==0) + // { + // Response.Redirect(FormsAuthentication.LoginUrl); + + // } + + //}//没有在菜单中则不做权限判断(暂时没有控制弹窗的统一权限校验) + var pm = PageManager.Instance; if (pm != null) { @@ -264,7 +314,7 @@ namespace FineUIPro.Web System.Web.UI.HtmlControls.HtmlGenericControl linkCtrl = new System.Web.UI.HtmlControls.HtmlGenericControl("link"); linkCtrl.Attributes["rel"] = "stylesheet"; linkCtrl.Attributes["type"] = "text/css"; - linkCtrl.Attributes["href"] = ResolveClientUrl("~/res/css/common.css?v" + GlobalConfig.ProductVersion); + /*linkCtrl.Attributes["href"] = ResolveClientUrl("~/res/css/common.css?v" + GlobalConfig.ProductVersion);*/ Header.Controls.AddAt(GetHeadStyleCSSIndex(), linkCtrl);