标签:
一 数据库
除了用户表之外,新建一个外联表<用户票据表> 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); } } }
标签:
原文地址:http://www.cnblogs.com/Smile-Jie/p/4802818.html