通用权限管理系统IP、MAC访问控制的实现
近日在吉日的指导下为通用权限管理系统增加了IP和MAC访问控制功能。
该功能可以同时对
- 单个IP(例如192.168.0.1)
- 一段IP (192.168.0.1-192.168.0.10)
- 带通配符的IP(192.168.0.*)
- MAC地址(00-16-36-3f-95-98)
进行访问控制。
1 |
系统通过配置config.xml 文件打开和关闭IP访问控制功能,默认为不开启。
1 2 | <!-- 是否开启IP限制--> < add key="CheckIPAddress" value="False"/> |
如果开启IP访问控制,编辑用户属性即可看到相应的操作按钮。
可以增加相应的IP地址和MAC地址,增加的地址是允许用户登录系统的地址。
用户的IP地址不在允许的范围内时,不允许登录。
如果MAC地址不在允许的范围内时,不允许登录。
对用户进行IP访问控制的业务逻辑主要通过BaseUserManager类中的LogOn方法实现。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | #region public BaseUserInfo LogOn(string userName, string password, string ipAddress, string macAddress, out string statusCode) 进行登录操作 /// <summary> /// 进行登录操作 /// 日志进行改进 /// </summary> /// <param name="userName">用户名</param> /// <param name="password">密码</param> /// <param name="ipAddress">IP地址</param> /// <param name="macAddress">MAC地址</param> /// <returns>用户类</returns> public BaseUserInfo LogOn( string userName, string password, string ipAddress, string macAddress, out string statusCode) { BaseUserInfo userInfo = null ; // 01. 查询数据库中的用户数据?只查询未被删除的 string [] names = new string [] { BaseUserTable.FieldDeletionStateCode, BaseUserTable.FieldUserName }; Object[] values = new Object[] { 0, userName }; DataTable dataTable = this .GetDT(names, values); // 02. 系统是否采用了密码加密策略? string encryptPassword = string .Empty; if (BaseSystemInfo.ServerEncryptPassword) { password = this .EncryptUserPassword(password); } // 03. 默认为用户没有找到状态,查找用户 // statusCode = StatusCode.UserNotFound.ToString(); // 这是为了达到安全要求,不能提示用户未找到,那容易让别人猜测到帐户 statusCode = StatusCode.ErrorLogOn.ToString(); BaseUserEntity userEntity = null ; // 04. 判断密码,是否允许登录,是否离职是否正确 foreach (DataRow dataRow in dataTable.Rows) { userEntity = new BaseUserEntity(dataRow); if (! string .IsNullOrEmpty(userEntity.AuditStatus) && userEntity.AuditStatus.EndsWith(AuditStatus.WaitForAudit.ToString())) { statusCode = AuditStatus.WaitForAudit.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户登录被拒,用户审核中。" ); return userInfo; } // 用户是否有效的 if (userEntity.Enabled == 0) { statusCode = StatusCode.LogOnDeny.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户被锁定,登录被拒绝,请联系系统管理员。" ); return userInfo; } // 用户是否有效的 if (userEntity.Enabled == -1) { statusCode = StatusCode.UserNotActive.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户未被激活,请及时激活用户帐户。" ); return userInfo; } // 05. 允许登录时间是否有限制 if (userEntity.AllowEndTime != null ) { userEntity.AllowEndTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, userEntity.AllowEndTime.Value.Hour, userEntity.AllowEndTime.Value.Minute, userEntity.AllowEndTime.Value.Second); } if (userEntity.AllowStartTime != null ) { userEntity.AllowStartTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, userEntity.AllowStartTime.Value.Hour, userEntity.AllowStartTime.Value.Minute, userEntity.AllowStartTime.Value.Second); if (DateTime.Now < userEntity.AllowStartTime) { statusCode = StatusCode.UserLocked.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户被锁定,登录被拒绝,不得早于:" + userEntity.AllowStartTime.Value.ToString( "HH:mm" )); return userInfo; } } if (userEntity.AllowEndTime != null ) { if (DateTime.Now > userEntity.AllowEndTime) { statusCode = StatusCode.UserLocked.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户被锁定,登录被拒绝,不得晚于:" + userEntity.AllowEndTime.Value.ToString( "HH:mm" )); return userInfo; } } // 06. 锁定日期是否有限制 if (userEntity.LockStartDate != null ) { if (DateTime.Now > userEntity.LockStartDate) { if (userEntity.LockEndDate == null || DateTime.Now < userEntity.LockEndDate) { statusCode = StatusCode.UserLocked.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户被锁定,登录被拒绝,锁定开始日期:" + userEntity.LockStartDate.Value.ToString( "yyyy-MM-dd" )); return userInfo; } } } if (userEntity.LockEndDate != null ) { if (DateTime.Now < userEntity.LockEndDate) { statusCode = StatusCode.UserLocked.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户被锁定,登录被拒绝,锁定结束日期:" + userEntity.LockEndDate.Value.ToString( "yyyy-MM-dd" )); return userInfo; } } // 07. 是否检查用户IP地址,是否进行访问限制?, 管理员不检查IP if (BaseSystemInfo.CheckIPAddress && ! this .IsAdministrator(userEntity.Id.ToString())) { if (! string .IsNullOrEmpty(ipAddress) && ! this .CheckIPAddress(ipAddress, userEntity.Id.ToString())) { statusCode = StatusCode.ErrorIPAddress.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, ipAddress, UserInfo.IPAddress, "IPAddress 不正确。" ); return userInfo; } } // 08. 是否检查用户的网卡Mac地址,是否进行访问限制?管理员不检查 if (BaseSystemInfo.CheckIPAddress && ! this .IsAdministrator(userEntity.Id.ToString())) { if (! string .IsNullOrEmpty(macAddress) && ! this .CheckMacAddress(macAddress, userEntity.Id.ToString())) { statusCode = StatusCode.ErrorMacAddress.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, macAddress, UserInfo.IPAddress, "MacAddress 不正确。" ); return userInfo; } } // 09. 更新IP地址,更新MAC地址 this .SetProperty(userEntity.Id, BaseUserTable.FieldIPAddress, ipAddress); this .SetProperty(userEntity.Id, BaseUserTable.FieldMACAddress, macAddress); // 10. 只允许登录一次,需要检查是否自己重新登录了,或者自己扮演自己了 if ((UserInfo != null ) && (!UserInfo.Id.Equals(userEntity.Id.ToString()))) { if (BaseSystemInfo.CheckOnLine) { if (userEntity.UserOnLine > 0) { statusCode = StatusCode.ErrorOnLine.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "用户已在线,不允许重复登录。" ); return userInfo; } } } // 11. 密码是否正确(null 与空看成是相等的) if (!( string .IsNullOrEmpty(userEntity.UserPassword) && string .IsNullOrEmpty(password))) { bool userPasswordOK = true ; // 用户密码是空的 if ( string .IsNullOrEmpty(userEntity.UserPassword)) { // 但是输入了不为空的密码 if (! string .IsNullOrEmpty(password)) { userPasswordOK = false ; } } else { // 用户的密码不为空,但是用户是输入了密码 if ( string .IsNullOrEmpty(password)) { userPasswordOK = false ; } else { // 再判断用户的密码与输入的是否相同 userPasswordOK = userEntity.UserPassword.Equals(password); } } // 用户的密码不相等 if (!userPasswordOK) { BaseLogManager.Instance.Add(DbHelper, userEntity.Id.ToString(), userEntity.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userEntity.RealName, ipAddress, "密码错误,登录被拒绝。" ); statusCode = StatusCode.PasswordError.ToString(); return userInfo; } } // 12. 是否检查同时在线用户数量,是否超过了软件购买的许可? if (BaseSystemInfo.OnLineLimit > 0) { if ( this .CheckOnLineLimit()) { statusCode = StatusCode.ErrorOnLineLimit.ToString(); BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "已超出用户在线数量上限" + BaseSystemInfo.OnLineLimit.ToString()); return userInfo; } } // 可以正常登录了 statusCode = StatusCode.OK.ToString(); // 13. 登录、重新登录、扮演时的在线状态进行更新 this .ChangeOnLine(userEntity.Id.ToString()); userInfo = this .ConvertToUserInfo(userEntity); // 获得员工的信息 if (userEntity.IsStaff == 1) { /* BaseStaffManager staffManager = new BaseStaffManager(DbHelper, UserInfo); // 这里需要按 员工的用户ID来进行查找对应的员工-用户关系 BaseStaffEntity staffEntity = new BaseStaffEntity(staffManager.GetDT(BaseStaffTable.FieldUserId, userEntity.Id)); if (staffEntity.Id > 0) { userInfo = staffManager.ConvertToUserInfo(staffEntity, userInfo); } */ } userInfo.IPAddress = ipAddress; userInfo.MACAddress = macAddress; userInfo.Password = password; // 数据找到了,就可以退出循环了 break ; } // 14. 记录系统访问日志 if (statusCode == StatusCode.UserNotFound.ToString()) { BaseLogManager.Instance.Add(DbHelper, userName, UserInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userName, UserInfo.IPAddress, "没有找到用户名,登录被拒绝。" ); } if (statusCode == StatusCode.OK.ToString()) { BaseLogManager.Instance.Add(DbHelper, userEntity.Id.ToString(), userInfo.RealName, "LogOn" , AppMessage.BaseUserManager, "LogOn" , AppMessage.BaseUserManager_LogOn, userEntity.RealName, UserInfo.IPAddress, AppMessage.BaseUserManager_LogOnSuccess); userInfo.OpenId = this .UpdateVisitDate(userEntity.Id.ToString(), true ); } return userInfo; } #endregion |
以下是检查IP地址和MAC地址的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | #region private bool CheckIPAddress(string ipAddress, string userId) 检查用户IP地址 /// <summary> /// 检查用户IP地址 /// </summary> /// <param name="ipAddress">IP地址</param> /// <returns>是否符合限制</returns> private bool CheckIPAddress( string ipAddress, string userId) { bool returnValue = false ; string [] names = { BaseParameterTable.FieldParameterId, BaseParameterTable.FieldCategoryId, BaseParameterTable.FieldEnabled }; Object[] values = { userId, "IPAddress" , 1 }; DataTable dt = DbLogic.GetDT( this .DbHelper, BaseParameterTable.TableName, names, values); if (dt.Rows.Count > 0) { string parameterCode = string .Empty; string parameterCotent = string .Empty; for ( int i = 0; i < dt.Rows.Count; i++) { parameterCode = dt.Rows[i][BaseParameterTable.FieldParameterCode].ToString(); parameterCotent = dt.Rows[i][BaseParameterTable.FieldParameterContent].ToString(); switch (parameterCode) { //匹配单个IP case "Single" : returnValue = CheckSingleIPAddress(ipAddress, parameterCotent); break ; //匹配ip地址段 case "Range" : returnValue = CheckIPAddressWithRange(ipAddress, parameterCotent); break ; //匹配带掩码的地址段 case "Mask" : returnValue = CheckIPAddressWithMask(ipAddress, parameterCotent); break ; } if (returnValue) break ; } } return returnValue; } /// <summary> /// 检查是否匹配单个IP /// </summary> /// <param name="ipAddress"></param> /// <param name="sourceIp"></param> /// <returns></returns> private bool CheckSingleIPAddress( string ipAddress, string sourceIp) { return ipAddress.Equals(sourceIp); } /// <summary> /// 检查是否匹配地址段 /// </summary> /// <param name="ipAddress">192.168.0.8</param> /// <param name="ipRange">192.168.0.1-192.168.0.10</param> /// <returns></returns> private bool CheckIPAddressWithRange( string ipAddress, string ipRange) { //先判断符合192.168.0.1-192.168.0.10 的正则表达式 //在判断ipAddress是否有效 string startIp = ipRange.Split( '-' )[0]; string endIp = ipRange.Split( '-' )[1]; //如果大于等于 startip 或者 小于等于endip if (CompareIp(ipAddress, startIp) == 2 && CompareIp(ipAddress, endIp) == 0 || CompareIp(ipAddress, startIp) == 1 || CompareIp(ipAddress, endIp) == 1) { return true ; } return false ; } /// <summary> /// 比较两个IP地址,比较前可以先判断是否是IP地址 /// </summary> /// <param name="ip1"></param> /// <param name="ip2"></param> /// <returns>1:相等; 0:ip1小于ip2 ; 2:ip1大于ip2;-1 不符合ip正则表达式 </returns> public int CompareIp( string ip1, string ip2) { //if (!IsIP(ip1) || !IsIP(ip2)) //{ // return -1; //} String[] arr1 = ip1.Split( '.' ); String[] arr2 = ip2.Split( '.' ); for ( int i = 0; i < arr1.Length; i++) { int a1 = int .Parse(arr1[i]); int a2 = int .Parse(arr2[i]); if (a1 > a2) { return 2; } else if (a1 < a2) { return 0; } } return 1; } /// <summary> /// 检查是否匹配带通配符的IP地址 /// </summary> /// <param name="ipAddress">192.168.1.1</param> /// <param name="ipWithMask">192.168.1.*</param> /// <returns></returns> private bool CheckIPAddressWithMask( string ipAddress, string ipWithMask) { //先判断是否符合192.168.1.* //然后判断 string [] arr1 = ipAddress.Split( '.' ); string [] arr2 = ipWithMask.Split( '.' ); for ( int i = 0; i < arr1.Length; i++) { if (!(arr2[i].Equals( "*" ) || arr1[i].Equals(arr2[i]))) { return false ; } } return true ; } #endregion private bool CheckIPAddress( string [] ipAddress, string userId) { bool returnValue = false ; for ( int i = 0; i < ipAddress.Length; i++) { if ( this .CheckIPAddress(ipAddress[i], userId)) { returnValue = true ; break ; } } return returnValue; } #region private bool CheckMacAddress(string macAddress, string userId) 检查用户的网卡Mac地址 /// <summary> /// 检查用户的网卡Mac地址 /// </summary> /// <param name="macAddress">Mac地址</param> /// <returns>是否符合限制</returns> private bool CheckMacAddress( string macAddress, string userId) { bool returnValue = false ; string [] names = { BaseParameterTable.FieldParameterId, BaseParameterTable.FieldCategoryId, BaseParameterTable.FieldEnabled }; Object[] values = { userId, "MacAddress" , 1 }; DataTable dt = DbLogic.GetDT( this .DbHelper, BaseParameterTable.TableName, names, values); if (dt.Rows.Count > 0) { string parameterCode = string .Empty; string parameterCotent = string .Empty; for ( int i = 0; i < dt.Rows.Count; i++) { parameterCode = dt.Rows[i][BaseParameterTable.FieldParameterCode].ToString(); parameterCotent = dt.Rows[i][BaseParameterTable.FieldParameterContent].ToString(); returnValue = (macAddress.ToLower()).Equals(parameterCotent.ToLower()); //简单格式化一下 if (returnValue) break ; } } return returnValue; } #endregion private bool CheckMacAddress( string [] macAddress, string userId) { bool returnValue = false ; for ( int i = 0; i < macAddress.Length; i++) { if ( this .CheckMacAddress(macAddress[i], userId)) { returnValue = true ; break ; } } return returnValue; } |
另外,功能实现的过程中优化了获取IP地址和MAC地址的方法。代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | /// <summary> /// 获取当前使用的IPV4地址 /// </summary> /// <returns></returns> public static string GetIPAddress() { string ipAddress = string .Empty; System.Net.IPHostEntry ipHostEntrys = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()); List< string > ipList = GetIPAddressList(); foreach ( string ip in ipList) { ipAddress = ip.ToString(); break ; } return ipAddress; } /// <summary> /// 获取IPv4地址列表,注意优先级高的放在了后面 /// </summary> /// <returns></returns> public static List< string > GetIPAddressList() { List< string > ipAddressList = new List< string >(); IPHostEntry ipHostEntrys = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()); foreach (IPAddress ip in ipHostEntrys.AddressList) { if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { ipAddressList.Add(ip.ToString()); } } return ipAddressList; } /// <summary> /// /// </summary> /// <returns></returns> public static string GetMacAddress() { string macAddress = string .Empty; List< string > macAddressList = GetMacAddressList(); foreach ( string mac in macAddressList) { if (! string .IsNullOrEmpty(mac)) { macAddress = mac.ToString(); //格式化 macAddress = string .Format( "{0}-{1}-{2}-{3}-{4}-{5}" , macAddress.Substring(0, 2), macAddress.Substring(2, 2), macAddress.Substring(4, 2), macAddress.Substring(6, 2), macAddress.Substring(8, 2), macAddress.Substring(10, 2)); break ; } } return macAddress; } /// <summary> /// 获取MAC地址列表,注意优先级高的放在了后面,注意优先级高的放在了后面 /// </summary> /// <returns></returns> public static List< string > GetMacAddressList() { List< string > macAddressList = new List< string >(); NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface ni in networkInterfaces) { //过滤掉虚拟网卡、移动网卡和Loopback if (!ni.Description.Contains( "WiFi" ) && !ni.Description.Contains( "Loopback" ) && !ni.Description.Contains( "VMware" ) && ni.OperationalStatus == OperationalStatus.Up) { macAddressList.Add(ni.GetPhysicalAddress().ToString()); } } return macAddressList; } |
有待于进一步完善的地方:
1、我在测试的过程中,当同时启用无线网络和有线网络时,获取的IP到底是有线网络的IP还是无线网络的IP呢?? 以前问过群里说是用route print 命令 查看metric小的优先级高。可是有一次测试时依然获得了metric大的IP。
2、管理员手工增加IP地址或者MAC地址 时的工作量还是比较大的。我们知道在系统登录的时候保存了用户的IP地址和MAC,这样话如果增加一功能“使用最后一次登录的IP和MAC”来增加地址的话,能减轻管理员的负担。
谢谢大家指点。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步