位图算法在用户验证上的应用

前几天在博客园看到一个帖子,讨论两个整数集合比较的算法问题。呵呵,其实任何整数集合的问题都是可以通过位图算法解决。简单地说,就是把值转化为数组下标,将O(n)复杂度降低到O(1)复杂度来获得最高效率。当然,会牺牲一点点空间。

解决单纯的整数集合比较问题,只是纯理论的。实际上,位图算法可以应用在用户登录之后的接口验证上。服务端的设计其实也没什么复杂的地方,就是维护一个数组罢了。只不过这个数组并非是简单的整数集合,而是一个对象List。这个设计的最大优点是在验证方法中,不是通过find方法而是直接访问下标获得对象,更无需查询数据库,可谓是将时间消耗降低到了极致。

好吧,下面看代码,首先是Session类,该类承载了一些必要的用户信息。其中最关键的属性是ID,这个ID的值就是该对象在List<Session>中的下标值。

    public class Session
    {

        /// <summary>
        /// 自增ID
        /// </summary>
        public int ID { get; set; }

        /// <summary>
        /// 会话ID
        /// </summary>
        public Guid SessionId { get; set; }

        /// <summary>
        /// 登录用户ID
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 登录部门ID
        /// </summary>
        public Guid? DeptId { get; set; }

        /// <summary>
        /// 用户账号
        /// </summary>
        public string LoginName { get; set; }

        /// <summary>
        /// 登录用户名
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 登录部门全称
        /// </summary>
        public string DeptName { get; set; }

        /// <summary>
        /// WCF服务基地址
        /// </summary>
        public string BaseAddress { get; set; }

        /// <summary>
        /// 用户签名
        /// </summary>
        public string Signature { get; set; }

        /// <summary>
        /// 用户状态
        /// </summary>
        public bool Validity { get; set; }

        /// <summary>
        /// 用户机器码
        /// </summary>
        public string MachineId { get; set; }

        /// <summary>
        /// 上次连接时间
        /// </summary>
        public DateTime LastConnect { get; set; }

        /// <summary>
        /// 用户登录状态
        /// </summary>
        public LoginResult LoginStatus { get; set; }

    }

然后是OnlineManage类,这个类在服务被启动的时候实例化,并提供了一个验证会话合法性的静态方法。其中关键点是:var us = Sessions[obj.ID]这句,通过下标访问的方法,将时间复杂度降低到了O(1)。

    public class OnlineManage
    {

        /// <summary>
        /// 用户会话列表
        /// </summary>
        public static List<Session> Sessions { get; set; }

        /// <summary>
        /// 最大在线用户数
        /// </summary>
        public static int MaxAuthorized { get; set; }

        /// <summary>
        /// 构造方法
        /// </summary>
        public OnlineManage()
        {
            Sessions = new List<Session>();
            MaxAuthorized = Convert.ToInt32(ConfigurationManager.AppSettings["MaxAuthorized"]);
        }

        /// <summary>
        /// 会话合法性验证
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool Verification(Session obj)
        {
            if (obj == null || obj.ID >= Sessions.Count) return false;

            var us = Sessions[obj.ID];
            if (us.SessionId != obj.SessionId || us.Signature != obj.Signature || !us.Validity) return false;

            us.LastConnect = DateTime.Now;
            return true;
        }

    }

最后是登录验证方法,这个方法通过一个O(n)的方法判断传入的Session对象是否已经存在(以前登录过系统),如果没有的话,通过查询数据库来构建一个新的Session对象被加入List。最后,无论是否登录过系统,该方法都将返回客户端一个Session对象实体。客户端每次调用服务端接口的时候,就可以将Session作为参数来进行合法性验证。

        /// <summary>
        /// 获取用户登录结果
        /// </summary>
        /// <param name="obj">Session对象实体</param>
        /// <returns>Session对象实体</returns>
        public Session UserLogin(Session obj)
        {
            if (obj == null) return null;

            if (OnlineManage.Sessions.Count >= OnlineManage.MaxAuthorized)
            {
                obj.LoginStatus = LoginResult.Unauthorized;
                return obj;
            }

            var pw = obj.Signature;
            var us = OnlineManage.Sessions.Find(s => s.LoginName == obj.LoginName);
            if (us == null)
            {
                var user = CommonDAL.GetUser(obj.LoginName);
                if (user == null)
                {
                    obj.LoginStatus = LoginResult.NotExist;
                    return obj;
                }

                obj.ID = OnlineManage.Sessions.Count;
                obj.UserId = user.ID;
                obj.UserName = user.Name;
                obj.Signature = user.Password;
                obj.Validity = user.Validity;

                OnlineManage.Sessions.Add(obj);
                us = OnlineManage.Sessions[obj.ID];
            }
            else if (us.SessionId != Guid.Empty)
            {
                us.LoginStatus = us.MachineId != obj.MachineId ? LoginResult.Online : LoginResult.Multiple;
            }
            else
            {
                us.SessionId = obj.SessionId;
                us.LoginStatus = LoginResult.Success;
            }

            // 用户被封禁
            if (!us.Validity) us.LoginStatus = LoginResult.Banned;

            // 密码不正确
            if (us.Signature != pw) us.LoginStatus = LoginResult.Failure;

            us.LastConnect = DateTime.Now;
            return us;
        }

一些通过传入参数进行验证的例子,如退出后删除登录状态(将SessionId置为空GUID值)等。对了,还有一个好处是,只要一个账号被封禁,会立即生效而非等用户退出。

        /// <summary>
        /// 删除在线用户会话
        /// </summary>
        /// <param name="us">Session对象实体</param>
        /// <param name="sid">要删除Session的ID</param>
        /// <returns>bool 是否删除成功</returns>
        public bool DelOnlineUser(Session us, int? sid)
        {
            if (us == null) return false;

            if (!OnlineManage.Verification(us)) return false;

            OnlineManage.Sessions[sid ?? us.ID].SessionId = Guid.Empty;
            return true;
        }

        /// <summary>
        /// 根据ID封禁/解封用户
        /// </summary>
        /// <param name="us">用户会话</param>
        /// <param name="id">用户ID</param>
        /// <param name="validity">true:解封;false:封禁</param>
        /// <returns>bool 是否更新成功</returns>
        public bool UpdateUserStatus(Session us, Guid id, bool validity)
        {
            if (!OnlineManage.Verification(us)) return false;

            var sql = string.Format("update SYS_User set Validity = '{0}' where ID = '{1}'", validity, id);
            if (SqlHelper.SqlNonQuery(sql) > 0)
            {
                OnlineManage.Sessions.Find(s => s.UserId == id).Validity = validity;
                return true;
            }
            return false;
        }

这里基本上就写这些,更多的代码请移步我的code。嗯嗯,需要一点时间整理。

时间: 2024-11-03 21:51:53

位图算法在用户验证上的应用的相关文章

MVC WebApi 用户验证 (2)

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2) 前言: 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(65)-MVC WebApi 用户验证 (1) 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接

Oracle 用户验证日志

1.sysdba/sysoper 权限用户验证日志;2.非sysdba/sysoper 权限用户验证日志;3.关于sqlcode; 1.sysdba/sysoper 权限用户验证日志:在数据库设置了参数 audit_sys_operations=true 的情况下,系统会根据 audit_trail 参数的设置记录 sysdba/sysoper 权限用户日志到 audit_file_dest 参数设置的目录下,记录日志的内容包括(数据库启动操作.登录验证信息.DML操作),其它非 sysdba/

LDA工程实践之算法篇之(一)算法实现正确性验证(转)

研究生二年级实习(2010年5月)开始,一直跟着王益(yiwang)和靳志辉(rickjin)学习LDA,包括对算法的理解.并行化和应用等等.毕业后进入了腾讯公司,也一直在从事相关工作,后边还在yiwang带领下,与孙振龙.严浩等一起实现了一套大规模并行的LDA训练系统——Peacock.受rick影响,决定把自己对LDA工程实践方面的一些理解整理出来,分享给大家,其中可能有一些疏漏和错误,还请批评指正. Rickjin在<LDA数学八卦>[1]一文中已经对LDA的数学模型以及基本算法介绍得比

搭建文件共享服务器-samba 匿名和用户验证访问

本实验环境: 系统:centos7 samba服务:samba-4.4.4-9.el7.x86_64 samba的作用:samab是文件共享服务,打印机共享等,用于和windows一起工作. samba服务有两个服务程序,分别是smb和nmb.smb主要负责客户机提供服务器中的共享资源(文件和目录的访问) nmb负责提供NetBIOS协议的主机名称解析,便于windows网络中的主机进行查询服务. 实验前准备: systemctl stop firewalld.service ###这里是关闭防

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2)

前言: 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(65)-MVC WebApi 用户验证 (1) 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接口,利用系统权限管理接口,对每个接口进行授权(管理接口为选读部分,因为你需要阅读最开始权限管理部分(18-27节),才能阅读这部分) 开发环境: V

html5 如何实现客户端验证上传文件的大小

在HTML 5中,现在可以在客户端进行文件上传时的校验了,比如用户选择文件后,可以 马上校验文件的大小和属性等.本文章向码农介绍html5 如何实现客户端验证上传文件的大小,感兴趣的码农可以参考一下. 在HTML 5中,现在可以在客户端进行文件上传时的校验了,比如用户选择文件后,可以马上校验文件的大小和属性等,这其实时得益于浏览器端新增的对文件的校验能力,其中支持HTML 5的浏览器,都会实现W3C实现的文件API标准,其中可以读取客户端文件的各种信息和参数. 下面的例子如下,首先是HTML <

Nginx提供网站服务应用包括(虚拟主机、用户访问控制、用户验证、nginx平滑升级、防盗链)的配置

Nginx   开源且跨平台的软件    俄罗斯人开发的   提供网站服务  和  代理服务 Nginx 提供网站服务应用环境? 1.虚拟主机2.用户访问控制3.用户验证4.防盗链 实验环境: 安装软件:nginx-0.855.tar.gz 操作系统:centos6.5 实验:(一) 实验目的:nginx源码包的安装以及基本的使用. 安装源码包要安装的工具:开发工具 和开发环境 1.安装nginx源码包 建立ngix软件夹用来存放nginx软件包 添加一个进程的所有者和所属组为www,www为n

Windows Azure SSTP模式VPN Client使用AD域用户验证登录

我们上面一篇文章介绍了,如何在windows azure下搭建SSTP模式的vpn服务,搭建配置后我们遗留了一个,什么问题呢,我们都知道,一般的独立vpn是使用独立的账户及密码的,尤其是托管到外面的vpn服务器,无法使用AD域用户验证.这样会造成vpn用户拥有两套用户及密码,管理起来很不方便.再说说我的环境,我的环境是把vpn服务器放在了windows azure上,这样算来也是托管类型的,但是windows azure毕竟是微软出的,AD也是微软的,在设计上肯定考虑了,最终呢托管到window

cookie (储存在用户本地终端上的数据)

Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密).定义于 RFC2109 和 2965 中的都已废弃,最新取代的规范是 RFC6265[1]  .(可以叫做浏览器缓存) 中文名 储存在用户本地终端上的数据 外文名 Cookie 复数形式 Cookies 目录 1 技术简介 2 功能特点 3 具体含义 4 诞生时间 5 主要用途 6 生存周期 7 识别功能 8 脚本攻击 9 相关问题 10 设置Co