using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; using Aitex.Common.Util; using Aitex.Core.RT.Log; using MECF.Framework.Common.Account.Permissions; namespace MECF.Framework.Common.Account.Extends { /// /// 角色账号加载器,从_AccountEx.xml文件加载角色。 /// public class RoleAccountLoader : XmlLoader { #region Variables private const string NODE_NAME_PERMS_GROUP = "Perms"; private const string NODE_NAME_PERMS_ITEM = "Perm"; private readonly MenuLoader _menuLoader; private List _roleList; private List _accountList; #endregion #region Constructors /// /// 创建角色加载器对象实例。 /// /// 角色配置文件名称,通常为_Account.xml public RoleAccountLoader(string fileName) : base(fileName) { _menuLoader = new MenuLoader(PathManager.GetCfgDir() + "menu.xml"); _menuLoader.Load(); } #endregion #region Methods /// /// 获取配置文件中定义的所有菜单项。 /// /// public List GetAllMenus() { return _menuLoader.MenuList; } /// /// 获取所有非超级用户角色列表。 /// /// public List GetRoles(bool includeSuper = false) { if (includeSuper) return _roleList; return _roleList.Where(x => !x.IsSuper).ToList(); } /// /// 获取所有非超级用户账号列表。 /// /// public List GetAccounts(bool includeSuper = false) { if (includeSuper) return _accountList; return _accountList.Where(x => !x.IsSuper).ToList(); } /// /// 解析Account.xml文件。 /// protected override void AnalyzeXml() { if (XmlDoc == null) { return; } var roleItems = from r in XmlDoc.Descendants("roleItem") select (r); var list = new List(); foreach (var roleNode in roleItems) { var strRoleId = roleNode.Attribute("id").Value; var strRoleName = roleNode.Attribute("name").Value; var strIsAutoLogout = roleNode.Attribute("autologout").Value; var strAutoLogoutTime = roleNode.Attribute("logouttime").Value; int.TryParse(strAutoLogoutTime, out var logoutTime); var isAutoLogout = ((strIsAutoLogout == "1")); var strBuildIn = roleNode.Attribute("buildin")?.Value ?? "false"; if (!bool.TryParse(strBuildIn, out var isBuildIn)) isBuildIn = false; // ID为0 ~ 3的角色强制为系统内置角色,禁止删除 if (strRoleId is "0" or "1" or "2" or "3") isBuildIn = true; var strDescription = roleNode.Attribute("description")?.Value ?? ""; // 旧版的权限保存方式为字符串形式,新版更改为节点列表。 // 为兼容旧格式,此处应该判断roleNode节点中的内容,将旧版自动转换为PermissionControlItem列表 if (roleNode.FirstNode is XText) { // 旧版 var permContent = roleNode.Value; var helper = new PermissionHelper(); helper.ParsePermission(permContent); var role = new Role(strRoleId, strRoleName, isAutoLogout, logoutTime, helper.MenuPermissionDictionary, isBuildIn, strDescription); list.Add(role); } else { // 新版 var permList = new Dictionary(); foreach (var grpPerms in roleNode.Elements(NODE_NAME_PERMS_GROUP)) { foreach (var xe in grpPerms.Elements(NODE_NAME_PERMS_ITEM)) { var permName = xe.Attribute("name")?.Value; var strPermValue = xe.Attribute("value")?.Value ?? "1"; if (!int.TryParse(strPermValue, out var permValue)) permValue = (int)MenuPermissionEnum.MP_NONE; if (!string.IsNullOrEmpty(permName)) permList[permName] = (MenuPermissionEnum)permValue; } } var role = new Role(strRoleId, strRoleName, isAutoLogout, logoutTime, permList, isBuildIn, strDescription); list.Add(role); } } var roleAdmin = new Role("-1", "Administrators", true, 20, null, true, null) { IsSuper = true }; list.Add(roleAdmin); _roleList = list; var users = from r in XmlDoc.Descendants("userItem") select (r); var lstUsers = new List(); foreach (var userNode in users) { var lstRolesBelongTo = new List(); var strUserId = userNode.Attribute("id").Value; var strLoginName = userNode.Attribute("loginname").Value; var strPassword = Decrypt(userNode.Attribute("password").Value); var strFirstName = userNode.Attribute("firstname").Value; var strLastName = userNode.Attribute("lastname").Value; var strEmail = userNode.Attribute("email").Value; var strDescription = ""; if (userNode.Attribute("description") != null) { strDescription = userNode.Attribute("description").Value; } var userRoles = from ro in userNode.Descendants("role") select (ro); foreach (var userRoleNode in userRoles) { var strRoleId = userRoleNode.Attribute("id").Value; lstRolesBelongTo.Add(strRoleId); } var item3 = new AccountEx(strUserId, strLoginName, strPassword, strFirstName, strLastName, strEmail, lstRolesBelongTo, strDescription); lstUsers.Add(item3); } var admin = new AccountEx("-1", "sic_admin", "sic_admin", "", "", "", new List { "-1" }) { IsSuper = true }; lstUsers.Add(admin); var readOnly = new AccountEx("-2", "Read-Only", "read-only", "", "", "", new List { "-1" }) { IsSuper = true }; lstUsers.Add(readOnly); _accountList = lstUsers; } /// /// 获取一个可用的角色ID。 /// /// public string GetAvailableRoleID() { // 4以下的ID为系统保留ID。 var id = 4; while (true) { var ro = _roleList.FirstOrDefault(x => x.RoleId == id.ToString()); if (ro == null) break; if (id >= 10000) throw new IndexOutOfRangeException("no available role ID."); id++; } return id.ToString(); } /// /// 更新指定的角色。 /// /// /// public bool UpdateRole(Role newRole) { var oldRole = _roleList.Find((Role item) => item.RoleId == newRole.RoleId); if (oldRole == null) _roleList.Add(newRole); else _roleList[_roleList.IndexOf(oldRole)] = newRole; var doc = XmlDoc; var roleToUpdate = doc.Descendants("roleItem").FirstOrDefault(x => x.Attribute("id").Value == newRole.RoleId); if (roleToUpdate != null) { // 修改现有的Role roleToUpdate.RemoveNodes(); } else { // 新增Role roleToUpdate = new XElement("roleItem"); doc.Root.Element("roles").Add(roleToUpdate); } // 设置属性 roleToUpdate.SetAttributeValue("id", newRole.RoleId); roleToUpdate.SetAttributeValue("name", newRole.RoleName); roleToUpdate.SetAttributeValue("autologout", (newRole.IsAutoLogout ? "1" : "0")); roleToUpdate.SetAttributeValue("logouttime", newRole.LogoutTime.ToString()); roleToUpdate.SetAttributeValue("buildin", newRole.IsBuildIn.ToString()); roleToUpdate.SetAttributeValue("description", newRole.Description); // 创建权限清单 var permList = new XElement(NODE_NAME_PERMS_GROUP); foreach (var perm in newRole.PermissionControlItems) permList.Add(new XElement(NODE_NAME_PERMS_ITEM, new XAttribute("name", perm.Key), new XAttribute("value", (int)perm.Value))); roleToUpdate.Add(permList); doc.Save(FileName); return true; } /// /// 删除指定ID的角色。 /// /// /// public bool DeleteRole(string roleId) { Load(); var roleToDelete = _roleList.Find((Role item) => item.RoleId == roleId); if (roleToDelete != null) { _roleList.Remove(roleToDelete); var xmlDoc = XmlDoc; var list = (from m_xRole in xmlDoc.Descendants("roleItem") where m_xRole.Attribute("id").Value == roleId select m_xRole).ToList(); if (list.Count > 0) { list[0].Remove(); foreach (var item in _accountList) { if (item.RoleIDs.Contains(roleToDelete.RoleId)) { item.RoleIDs.Remove(roleToDelete.RoleId); } } list = (from m_xRole in xmlDoc.Descendants("role") where m_xRole.Attribute("id").Value == roleToDelete.RoleId select m_xRole).ToList(); if (list.Count > 0) { list.Remove(); } xmlDoc.Save(FileName); return true; } return false; } return false; } private Dictionary GetRolePermission(string roleId) { var perms = _roleList.FirstOrDefault(x => x.RoleId == roleId)?.PermissionControlItems; if(perms == null) LOG.Error($"Unable to find the Role by ID {roleId}, or the permission list is empty."); return perms; } /// /// /// /// /// public List GetAccessibleMenusByRole(string roleId) { var list = new List(); var rolePermission = GetRolePermission(roleId); if (rolePermission == null) return null; foreach (var menu in GetAllMenus()) { var appMenusHasPerm = new List(); foreach (var menuItem in menu.MenuItems) { if (!rolePermission.TryGetValue(menuItem.MenuID, out var perm)) { // 当前菜单的权限未定义 LOG.Error($"The permission of {menuItem.MenuID} is not defined."); continue; } var appMenu = new AppMenu(menuItem.MenuID, menuItem.ViewModel, menuItem.ResKey, null, menuItem.Description) { System = menuItem.System, AlarmModule = menuItem.AlarmModule, Permission = perm }; if (appMenu.Permission > MenuPermissionEnum.MP_NONE) { appMenusHasPerm.Add(appMenu); } } if (appMenusHasPerm.Count > 0) { var appMenu2 = new AppMenu(menu.MenuID, menu.ViewModel, menu.ResKey, appMenusHasPerm, menu.Description); appMenu2.System = menu.System; appMenu2.AlarmModule = menu.AlarmModule; list.Add(appMenu2); } } return list; } /// /// 获取指定角色指定菜单的访问权限。 /// /// /// /// public MenuPermissionEnum GetMenuPermission(string roleId, string menuName) { var rolePermission = GetRolePermission(roleId); if (rolePermission.TryGetValue(menuName, out var perm)) return perm; return MenuPermissionEnum.MP_NONE; } /// /// 保存账号。如果当前账号ID已存在,则更新账号;否则新建账号并保存。 /// /// /// public bool UpdateAccount(AccountEx newAccount) { var accountEx = _accountList.Find((AccountEx item) => item.UserId == newAccount.UserId); if (accountEx == null) { _accountList.Add(newAccount); } else { _accountList[_accountList.IndexOf(accountEx)] = newAccount; } var xmlDoc = XmlDoc; var list = (from xAccount in xmlDoc.Descendants("userItem") where xAccount.Attribute("id")?.Value == newAccount.UserId select xAccount).ToList(); if (list.Count > 0) { list[0].SetAttributeValue("loginname", newAccount.LoginName); list[0].SetAttributeValue("password", Encrypt(newAccount.Password)); list[0].SetAttributeValue("firstname", newAccount.FirstName); list[0].SetAttributeValue("lastname", newAccount.LastName); list[0].SetAttributeValue("email", newAccount.Email); list[0].SetAttributeValue("description", newAccount.Description); list[0].Element("rolegroup").RemoveAll(); foreach (var roleID in newAccount.RoleIDs) { list[0].Element("rolegroup").Add(new XElement("role", new XAttribute("id", roleID))); } } else { var xElement = new XElement("userItem", new XAttribute("id", newAccount.UserId), new XAttribute("loginname", newAccount.LoginName), new XAttribute("password", Encrypt(newAccount.Password)), new XAttribute("firstname", newAccount.FirstName), new XAttribute("lastname", newAccount.LastName), new XAttribute("email", newAccount.Email), new XAttribute("description", newAccount.Description), new XElement("rolegroup")); foreach (var roleID2 in newAccount.RoleIDs) { xElement.Element("rolegroup").Add(new XElement("role", new XAttribute("id", roleID2))); } xmlDoc.Root.Element("users").Add(xElement); } xmlDoc.Save(FileName); return true; } /// /// 删除账号。 /// /// /// public bool DeleteAccount(string id) { var accountEx = _accountList.Find((AccountEx item) => item.UserId == id); if (accountEx != null) { _accountList.Remove(accountEx); var xdoc = XmlDoc; var list = (from xAccount in xdoc.Descendants("userItem") where xAccount.Attribute("id")?.Value == id select xAccount).ToList(); if (list.Count > 0) { list[0].Remove(); xdoc.Save(FileName); return true; } return false; } return false; } /// /// 加密字符串。 /// /// /// public string Encrypt(string encrytStr) { if (string.IsNullOrWhiteSpace(encrytStr)) { return string.Empty; } try { var bytes = Encoding.UTF8.GetBytes(encrytStr); return Convert.ToBase64String(bytes); } catch { return encrytStr; } } /// /// 解密字符串。 /// /// /// public string Decrypt(string decryptStr) { if (string.IsNullOrWhiteSpace(decryptStr)) { return string.Empty; } try { var bytes = Convert.FromBase64String(decryptStr); return Encoding.UTF8.GetString(bytes); } catch { return decryptStr; } } #endregion } }