通用权限管理系统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)

进行访问控制。


系统通过配置config.xml 文件打开和关闭IP访问控制功能,默认为不开启。

 <!-- 是否开启IP限制-->
 <add key="CheckIPAddress" value="False"/>

wps_clip_image-26206

如果开启IP访问控制,编辑用户属性即可看到相应的操作按钮。

wps_clip_image-26321

可以增加相应的IP地址和MAC地址,增加的地址是允许用户登录系统的地址。

wps_clip_image-14510

用户的IP地址不在允许的范围内时,不允许登录。

wps_clip_image-4894

如果MAC地址不在允许的范围内时,不允许登录。

wps_clip_image-26598

对用户进行IP访问控制的业务逻辑主要通过BaseUserManager类中的LogOn方法实现。代码如下:

 #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地址的方法。

 #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地址的方法。代码如下

/// <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”来增加地址的话,能减轻管理员的负担。

 

谢谢大家指点。

posted @ 2011-07-13 19:24  clude2010  阅读(1271)  评论(2编辑  收藏  举报