• Web单浏览器登录


    一  数据库

      除了用户表之外,新建一个外联表<用户票据表> fdUsTiUserID,fdUsTiType,fdUsTiTicket 分别对应用户ID,客户端类型(PC,mobile) 票据值,每次用户登录时将票据信息更新到数据库

    二 思路

      1.获取用户: 

       通过检查当前请求的Sessions.UserId或者Cookies.UserId是否存在;Sessions.UserId存在时直接从缓存获取用户数据,缓存不存在则从数据库中直接获取;否则通过Cookies.UserId和票据从数据库中读取用户信息;(票据也是存在客户端 Cookies.UserTicket)

      2.判断用户合法

      通过第一步的获取用户信息之后判断用户是否为null,如果为null直接返回,如果不为null则判断缓存票据和当前请求票据(Cookies.UserTicket)是否一致,如果一致则返回当前用户,不一致则判断为已经异地登录 当前票据失效,返回null;(如果请求合法 返回之前判断Session.UserId是否存在,不存在的话重建SessionId)

    三 关于多客户端缓存用户等的共享

         同一用户多客户端登录 会在多客户端存储用户的Session.UserId和针对各个客户端的不同票据值 然后只缓存一份用户信息 通过每次请求时的票据合法性来判断是否登录

      下面是以上的代码

          

    public static GP_Users_Model user
            {
                get
                {
                    GP_Users_Model _user = null;                 
                    if (Sessions.UserID != null && (int)Sessions.UserID > 0)
                    {
                        //从缓存中获取用户,如果为null直接从数据库中根据ID读取(可能缓存过期,则直接从数据库中读取)
                        _user = GP_Users_Bll.Instance.GetLoginUser((int)Sessions.UserID);
                    }
                    else if (Cookies.UserID != null && Cookies.UserID > 0 && Cookies.UserTicket != "")
                    {
                        //根据用户ID和登录票据从数据库中读取用户
                        _user = GP_Users_Bll.Instance.GetLoginUser((int)Cookies.UserID, Cookies.UserTicket);
                    }
                    if (_user == null) return null;  //用户不存在
                    
                    //检查用户当前请求票据是否合法
                    if (!loginCacheTicket.Test(_user.fdUserID.Value, Cookies.UserTicket))
                    {
                        //重置该用户票据缓存,将用户的所有客户端票据缓存到Rediss
                        GP_Users_Bll.Instance.ResetUserTicket(_user.fdUserID.Value);
                    }
                    //重置该用户票据缓存后再次检查
                    if (!loginCacheTicket.Test(_user.fdUserID.Value, Cookies.UserTicket))  
                        return null;//异地登录
                    
                    //如果Session过期 则重建Session
                    if( Sessions.UserID == null || ( int ) Sessions.UserID < 0 )
                        Sessions.UserID = _user.fdUserID;
                    return _user;
                }
            }

    Sessions类 

      说明:所有用户都用的同一个SessionNames.User_Id不会导致用户的缓存SessionId被覆盖,在底层有处理 具体的下面会有描述 关于Redis实现Session

    public class SessionNames
    {
        public const string User_Id    ="USERID";
    }
    
    public static class Sessions
    {
        public static int? UserID 
        {
            get
            {
                try { return (int)GetSession(SessionNames.User_Id); }
                    catch { return null; }            
            }
            set
            {
                SetSession(SessionNames.User_Id, value);
            }
        }
        public static object GetSession(string name)
        {
            return GPRedisSessions.Instance.GetSession(name);
            //if (HttpContext.Current.Session[name] == null) return null;
            //return HttpContext.Current.Session[name];
        }
        public static object SetSession(string name, object value)
        {
            return GPRedisSessions.Instance.SetSession(name, value);
            //HttpContext.Current.Session[name] = value;
            //return value;
        }
    }

    Cookies类
    public class CookieNames
    {
        public const string User_Id    ="UID";
        public const string User_Ticket="USERTICKET";
    }
    
    public static class Cookies
    {
        public static string UserTicket 
        {
            get
            {
                try { return GetCookie(CookieNames.User_Ticket); }
                catch { return null; }
            }
            set { SetCookie(CookieNames.User_Ticket, value); }
        }
        
        public static string UserID
        {
            get
            {
                try { return GetCookie(CookieNames.User_Id); }
                catch { return null; }
            }
            set { SetCookie(CookieNames.User_Id, value); }
        }
        
        public static string GetCookie(string name)
        {
            if (HttpContext.Current.Request.Cookies[name] == null || HttpContext.Current.Request.Cookies[name].Value == null) return "";
            return UrlEncoder.UnEscape(HttpContext.Current.Request.Cookies[name].Value);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="expires">超时时间,不设置则为浏览器生命周期</param>
        /// <returns></returns>
        public static string SetCookie(string name, string value)
        {
            SetCookie(name, value, null);
            return value;
        }
        public static string SetCookie(string name, string value, DateTime? expires)
        {
            return SetCookie(name, value, expires, true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="expires"></param>
        /// <param name="httpOnly">是否仅服务器端可读</param>
        /// <returns></returns>
        public static string SetCookie(string name, string value, DateTime? expires, bool httpOnly)
        {
            if (HttpContext.Current.Request.Cookies[name] == null)
            {
                HttpCookie co = new HttpCookie(name);
                co.HttpOnly = httpOnly;
                HttpContext.Current.Request.Cookies.Add(co);
            }
            HttpContext.Current.Request.Cookies[name].Value = UrlEncoder.Escape(value);
            if (expires != null) HttpContext.Current.Request.Cookies[name].Expires = (DateTime)expires;
    
            if (HttpContext.Current.Response.Cookies[name] == null)
            {
                HttpCookie co = new HttpCookie(name);
                co.HttpOnly = httpOnly;
                HttpContext.Current.Response.Cookies.Add(co);
            }
            HttpContext.Current.Response.Cookies[name].Value = UrlEncoder.Escape(value);
            if (expires != null) HttpContext.Current.Response.Cookies[name].Expires = (DateTime)expires;
            return value;
        }
    }
    
    

    类 GPRedisSessions Redis存储Session

      说明:主要是根据 GPRedisSessionID.Instance.Get()返回的值来确定Session值不会被覆盖, 所有存储到Redis的Session都会在客户端存一个access值     

    internal class GPRedisSessions
        {
            private static string GetKey(string sessionName)
            {
                return "MYWEB." + sessionName + "." + GPRedisSessionID.Instance.Get();
            }
    
    
            private static GPRedisSessions instance = new GPRedisSessions();
            public static GPRedisSessions Instance
            {
                get { return instance; }
            }
            private GPRedisSessions() { }
    
            public void Clear()
            {
                using (RedisClient RdsClient = RedisClientHelper.RdsClient)
                {
                    foreach (string name in SessionNames.GetAllNames()) RdsClient.Remove(GetKey(name));
                }
            }
    
            public void Remove(string name)
            {
                using (RedisClient RdsClient = RedisClientHelper.RdsClient)
                {
                    RdsClient.Remove(GetKey(name));
                }
            }
    
            public object GetSession(string name)
            {
                using (RedisClient RdsClient = RedisClientHelper.RdsClient)
                {
                    byte[] v = RdsClient.Get(GetKey(name));
                    if (v == null || v.Length == 0) return null;
                    return RedisClientHelper.BytesToObject(v);
                }
            }
    
            public object SetSession(string name, object value)
            {
                using (RedisClient RdsClient = RedisClientHelper.RdsClient)
                {
                    if (value == null) { Remove(name); return null; }
                    RdsClient.Set(GetKey(name), RedisClientHelper.ObjectToBytes(value), DateTime.Now.AddDays(30));
                    return value;
                }
            }
        }
    
    
    internal class GPRedisSessionID : ISessionID
        {
            private static GPRedisSessionID instance = new GPRedisSessionID();
            public static GPRedisSessionID Instance
            {
                get { return instance; }
            }
            private GPRedisSessionID() { }
    
            private static string New_Redis_Session_ID
            {
                get
                {
                    return Common.Security.Secure.MD5_32(RandomValue.Random_Int(1000, 9999) + RequestHelper.GetClientIP() + DateTime.Now.ToString());
                }
            }
    
            public string Get()
            {
                using (RedisClient RdsClient = RedisClientHelper.RdsClient)
                {
                    string ky = string.Empty;
                    if (Cookies.ContainCookie(CookieNames.Open_Access_ID))
                    {
                        ky = RedisKeysConfig.Key_CookieSessionID + "." + Cookies.Open_Access_ID;
                        try
                        {
                            DateTime dt = RdsClient.Get<DateTime>(ky);
                            if (dt != null && dt > DateTime.Now)
                            {
                                if (dt < DateTime.Now.AddHours(2)) RdsClient.Expire(ky, 10800);
                                return Cookies.Open_Access_ID;
                            }
                        }
                        catch { }
                    }
                    string v = string.Empty;
                    //冲突检测,如果冲突则重新分配
                    while (v == string.Empty || RdsClient.GetEntryType(ky) > 0)
                    {
                        v = New_Redis_Session_ID;
                        ky = RedisKeysConfig.Key_CookieSessionID + "." + v;
                    }
                    Cookies.SetCookie(CookieNames.Open_Access_ID, v);
                    RdsClient.Set<DateTime>(ky, DateTime.Now.AddHours(3), DateTime.Now.AddHours(3));
                    return v;
                }
            }
        }
    LoginCache 添加用户缓存类
    public class LoginCache
    {
            const string key="Login_";
            public static bool LoginTest(int uid)
            {
                using (IRedisClient redis = RedisClientHelper.RdsClient)
                {
                    return redis.Get<GP_Members_Model>(key+uid) != null;
                }
            }
            public static void LoginAdd(int uid, GP_User_Model v)
            {            
                using (IRedisClient redis = RedisClientHelper.RdsClient)
                {
                    redis.Set<GP_User_Model>(key+uid, v, TimeSpan.FromMinutes(15));
                }      
            }
            public static void LoginRemove(int uid)
            {
                using (IRedisClient redis = RedisClientHelper.RdsClient)
                {
                    redis.Remove(key+uid);
                }           
            }
            public static GP_User_Model GetLoginCache(int uid)
            {
                using (IRedisClient redis = RedisClientHelper.RdsClient)
                {
                    return redis.Get<GP_User_Model>(key+uid);
                }
            }
    }
    
    
    
     
  • 相关阅读:
    Phoenix SQL总结
    awk基本用法
    集群性能调优-速度篇
    集群基准性能测试
    服务器基础环境搭建
    kafka命令行操作
    九、spring boot--JPA实现分页和枚举转换
    八、spring boot--mybatis框架实现分页和枚举转换
    七、spring boot开发web应用--mybatis-plus框架实现分页和枚举转换
    六、spring boot开发web应用--mybatis-plus为简化而生
  • 原文地址:https://www.cnblogs.com/jieliu726/p/4802818.html
Copyright © 2020-2023  润新知