http://www.cnblogs.com/wangrudong003/p/6435013.htmlhtml
本章将要和你们分享的是一个单点登陆中间件,中间件听起来高深其实这里只是吧单点登陆要用到的逻辑和处理流程封装成了几个方法而已,默认支持采用redis服务保存session的方式,也可使用参数Func<>方法来作自定义session存储操做的方式,就不用我默认提供的redis存储的方法了;要说本章内容的来源,实际上是我在之前的ShenNiu.MVC管理系统中加入了最近作的调查问卷模块,这个问卷调查和ShenNiu.MVC不是一个站点,可是个人问卷调查系统可定在维护问卷或题目的时候须要登陆人的信息,我又不想再单独弄一套帐号方面的程序了,因此就采用这种单点登陆模式,以此来提供调查问卷的所须要的用户信息,以及为了避免久的未来本身写的某个模块也须要管理用户信息的话,就能省略掉用户模块了,不得不说单点登陆在此刻发挥的做用之大;本章内容但愿你们可以喜欢,也但愿各位多多"扫码支持"和"推荐"谢谢!若是您想要和咱们交流更多mvc相关信息能够来Ninesky框架做者:洞庭夕照 指定的官方群 428310563交流;git
» 单点登陆验证手画示例图web
» ShenNiuApi.SDK封装中间件代码redis
» 调查问卷系统使用中间件示例数据库
» 推广调查问卷系统api
下面一步一个脚印的来分享:浏览器
» 单点登陆验证手画示例图服务器
首先,咋们要作一个简易的单点登陆功能,须要明白其执行的流程和运做的原理,这里将图文并茂重点提出我认为关键的地方,先上一幅手工图:微信
看起来图画的不是很好看,不过我想表达的意思感受仍是表达清楚了;做为一个单点登陆验证模块,最主要的流程有:cookie
1. 未登陆时:提供统一登陆入口=》去数据库验证帐号正确性=》存储会话session(这里采用redis存储token和用户登录信息,利用其数据过时策略充当session会话机制)=》重定向到redirectUrl指定的地址
2. 已登陆时:获取站点的cookie存储的sessionId(token)=》调用验证token有效接口=》这里有两种状况(a,b)
a) 有效token=》获取登陆用户的session存储的信息(redis存储的value信息)
b) 无效token=》返回无效信息,构造登陆入口地址
经过上面分析,大体的流程应该很明确了下面咱们就来看封装的代码;
» ShenNiuApi.SDK封装中间件代码
这里要看的是中间件的3个方法:SsoMiddleWareServer(登陆入口操做),SsoMiddleWareClient(Token验证及获取登陆信息),SsoMiddleWareLoginOut(注销操做);这里我已经把方法打包放到了nuget上: Install-Package ShenNiuApi.SDK ,只须要下载最新的sdk,就能轻松帮您实现一个单点登陆架构,下面来看具体的代码;
SsoMiddleWareServer(登陆入口操做):
1 /// <summary> 2 /// 单点登陆操做 SSOMiddleWare服务端(方法功能: 3 /// 1.生成sessionId 4 /// 2.存储session到redis(60分钟失效)或者自定义sessionStoreFunc方法中 5 /// 3.构造带有token的重定向地址) 6 /// 注:默认采用redis保存session,所以须要在conf中配置ReadAndWritePorts和OnlyReadPorts两个appSettings节点: 7 /// ReadAndWritePorts在conf中配置格式如:pwd@ip:port,多个使用‘|’隔开 实例:shenniubuxing3@127.0.0.1:6377 8 /// OnlyReadPorts在conf中配置格式如:pwd@ip:port,多个使用‘|’隔开 实例:shenniubuxing3@127.0.0.1:6377 9 /// </summary> 10 /// <typeparam name="TUserBaseInfo">存储登陆信息的对象</typeparam> 11 /// <param name="userBaseInfo">登陆信息</param> 12 /// <param name="redirectUrl">重定向地址(注:格式应为http://或者https://;并通过UrlEncode转码后的地址;若是是同站点下面的话无需http://标记)</param> 13 /// <param name="token">执行方法无误后ref返回惟一的token(注:token生成规则是惟一的tokenKey+guid+时间戳)</param> 14 /// <param name="tokenKey">生成token的Key(默认:666666)</param> 15 /// <param name="sessionStoreFun">自定义session存储方法(提供自定义操做保存session的方法,覆盖默认的reids存储方式)</param> 16 /// <param name="timeOut">60(分钟)</param> 17 /// <returns>追加有token的重定向地址</returns> 18 public string SsoMiddleWareServer<TUserBaseInfo>(TUserBaseInfo userBaseInfo, string redirectUrl, ref string token, string tokenKey = "666666", Func<TUserBaseInfo, bool> sessionStoreFun = null, int timeOut = 60) 19 where TUserBaseInfo : class,new() 20 { 21 var returnUrl = string.Empty; 22 try 23 { 24 //非空验证 25 if (string.IsNullOrWhiteSpace(redirectUrl) || userBaseInfo == null) { return returnUrl; } 26 27 //生成Token 28 token = Md5Extend.GetSidMd5Hash(tokenKey); 29 30 // ShenNiuApi默认的Redis存储session 31 if (sessionStoreFun == null && userBaseInfo != null) 32 { 33 if (!CacheRepository.Current(CacheType.RedisCache).SetCache<TUserBaseInfo>(token, userBaseInfo, timeOut, true)) { return returnUrl; } 34 } 35 else { if (!sessionStoreFun(userBaseInfo)) { return returnUrl; } } 36 37 //通域名站内系统登陆 38 if (!Uri.IsWellFormedUriString(redirectUrl, UriKind.Absolute)) 39 { 40 returnUrl = redirectUrl; 41 return returnUrl; 42 } 43 44 #region 解析并构造跳转连接 45 redirectUrl = HttpUtility.UrlDecode(redirectUrl); 46 redirectUrl = redirectUrl.TrimEnd('&'); 47 redirectUrl = Regex.Replace(redirectUrl, "(&)?token=[^&]+(&)?", ""); 48 Uri uri = new Uri(redirectUrl); 49 var queryStr = uri.Query; 50 redirectUrl += queryStr.Contains('?') ? "" : "?"; 51 redirectUrl += string.IsNullOrWhiteSpace(queryStr.TrimStart('?')) ? "" : "&"; 52 returnUrl = string.Format("{0}token={1}", redirectUrl, token); 53 #endregion 54 } 55 catch (Exception ex) 56 { 57 throw new Exception(ex.Message); 58 } 59 finally 60 { 61 if (string.IsNullOrWhiteSpace(returnUrl)) { token = string.Empty; } 62 } 63 return returnUrl; 64 }
SsoMiddleWareClient(Token验证及获取登陆信息):
1 /// <summary> 2 /// 单点登陆操做 SSOMiddleWare客户端(方法功能: 3 /// 1.验证客户端是否有sid或者url地址中带有最新的token 4 /// 2.获取服务端session的基本信息(注:默认直接读取服务端的redis库,同server方法同样须要配置对应的帐号节点ReadAndWritePorts和OnlyReadPorts) 5 /// 3.从新设置客户端cookie有效期和服务端存储session的有效期) 6 /// </summary> 7 /// <typeparam name="TUserBaseInfo">登录用户信息对象</typeparam> 8 /// <param name="httpContext">上下文HttpContext</param> 9 /// <param name="ssoLoginUrl">sso统一登录入口地址</param> 10 /// <param name="redirectUrl">待重定向的地址</param> 11 /// <param name="userBaseInfo">获取的登录用户信息</param> 12 /// <param name="token">惟一token(即:sid)</param> 13 /// <param name="getOrsetSessionFun">自定义获取服务端用户信息方法而且同时要知足从新设置新的session有效时间</param> 14 /// <param name="sidName">cookie保存的sid名称</param> 15 /// <param name="timeOut">过时时间</param> 16 /// <returns></returns> 17 public string SsoMiddleWareClient<TUserBaseInfo>(HttpContext httpContext, string ssoLoginUrl, string redirectUrl, ref TUserBaseInfo userBaseInfo, ref string token, Func<string, int, TUserBaseInfo> getAndsetSessionFun = null, string sidName = "sid", int timeOut = 60) 18 where TUserBaseInfo : class,new() 19 { 20 var returnUrl = string.Empty; 21 try 22 { 23 userBaseInfo = default(TUserBaseInfo); 24 token = string.Empty; 25 if (string.IsNullOrWhiteSpace(ssoLoginUrl) || string.IsNullOrWhiteSpace(redirectUrl) || string.IsNullOrWhiteSpace(sidName)) { return returnUrl; } 26 27 //设置过时后验证url串 28 returnUrl = string.Format("{0}?returnUrl={1}", ssoLoginUrl, HttpUtility.UrlEncode(redirectUrl)); 29 30 //获取token 31 var cookie = httpContext.Request.Cookies.Get(sidName); 32 token = httpContext.Request.Params["token"]; 33 token = string.IsNullOrWhiteSpace(token) ? (cookie == null ? "" : cookie.Value) : token; 34 if (string.IsNullOrWhiteSpace(token)) { return returnUrl; } 35 36 //获取用户基本信息 37 if (getAndsetSessionFun != null) 38 { 39 userBaseInfo = getAndsetSessionFun(token, timeOut); 40 } 41 else 42 { 43 userBaseInfo = CacheRepository.Current(CacheType.RedisCache).GetCache<TUserBaseInfo>(token, true); 44 } 45 if (userBaseInfo == null) 46 { 47 //过时cookie,清空 48 if (cookie != null) 49 { 50 cookie.Expires = DateTime.Now.AddDays(-1); 51 httpContext.Response.SetCookie(cookie); 52 } 53 return returnUrl; 54 } 55 56 //cookie被清除,须要从新设置 57 if (cookie == null) 58 { 59 cookie = new HttpCookie(sidName, token); 60 cookie.Expires = DateTime.Now.AddMinutes(timeOut); 61 httpContext.Response.AppendCookie(cookie); 62 } 63 else 64 { 65 //登录验证都成功后,须要从新设置cookie中的toke失效时间 66 cookie.Value = token; 67 cookie.Expires = DateTime.Now.AddMinutes(timeOut); 68 httpContext.Response.SetCookie(cookie); 69 } 70 71 //设置服务端session的失效时间 72 if (getAndsetSessionFun == null) 73 { 74 CacheRepository.Current(CacheType.RedisCache).AddExpire(token, timeOut); 75 } 76 returnUrl = string.Empty; 77 }