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 }