十6、【適合中小企業的.Net輕量級開源框架】EnterpriseFrameWork框架核心類庫之單點登陸SSO

回《【開源】EnterpriseFrameWork框架系列文章索引》       html

EFW框架源代碼下載:http://pan.baidu.com/s/1qWJjo3Ujava

 

       單點登陸(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。web

 

如上圖,當用戶第一次訪問應用系統1的時候,由於尚未登陸,會被引導到認證系統中進行登陸;根據用戶提供的登陸信息,認證系統進行身份校驗,若是經過校驗,應該返回給用戶一個認證的憑據--ticket;用戶再訪問別的應用的時候,就會將這個ticket帶上,做爲本身認證的憑據,應用系統接受到請求以後會把ticket送到認證系統進行校驗,檢查ticket的合法性。若是經過校驗,用戶就能夠在不用再次登陸的狀況下訪問應用系統2和應用系統3了。安全

上面這段文字描敘是從網上摘抄的,以爲基本上把單點登陸的原理講得很清晰了;本章講解EFW框架中是如何實現單點登陸的以及框架中是如何使用的;框架

 

本文要點:ide

1.什麼狀況下會用到單點登陸ui

2.框架中的三種模式Web、Winform和WCF,分別是怎樣進行用戶驗證spa

3.單點登陸樣例.net

4.單點登陸SSO實現代碼3d

 

1.什麼狀況下會用到單點登陸

       剛開始框架中也是沒有單點登陸此模塊的,有一次須要在Winform系統中嵌入Web頁面,整合兩個系統。Web頁面的用戶信息驗證一直沒找到什麼好的解決辦法,剛開始的辦法是經過往網頁地址後面自動加上登陸用戶名和密碼,發送到後臺進行登陸;這樣也達到了整合的目的,可是總感受比較彆扭,直接把用戶名和密碼暴露在地址欄確定存在安全隱患。後來通過一番波折在網上找到相似的解決辦法,利用單點登陸的方案達到了比較好的效果;

       除了上面說的Winform系統中嵌入Web頁面這種狀況,還有常常在本身公司系統中整合一些合做夥伴的系統,如此打包銷售更有市場競爭力,這樣首要解決的問題也是登陸入口統一;現在行業軟件現狀,不像十年前了只有那麼一兩套系統,講究着用就好了,如今沒有用上十來個系統就不叫信息化了,因此你能提供一個單點登陸的解決方案也是一大賣點;再就是如今的軟件公司無論大小靠一個產品就能生存的很難了,基本都是最大化的挖掘客戶的需求,最好能提供一整套的解決方案,這些系統能總體銷售更好,而單個產品銷售也得支持。因此無論是客戶的需求仍是內部的產品都會存在系統間整合的問題,而利用單點登陸至少能解決用戶統一驗證的問題;

 

2.框架中的三種系統模式Web、Winform和WCF,分別是怎樣進行用戶驗證

先分析一下框架中的三種系統模式的用戶驗證是如何實現的,而後才能正確運用單點登陸的功能;

1)Web系統用戶驗證,輸入用戶名密碼登陸後,登陸界面向後臺發送登陸請求調用LoggingController執行用戶密碼驗證代碼,驗證正確後把用戶信息存入Session;以後全部界面操做向後臺發送請求,APIHttpHandler對象接收請求後,先判斷Session中是否存在用戶信息,只有存在才執行對應的控制器代碼,不然再返回錯誤信息給前臺;

 

這裏增長了一個系統配置參數TurnOnLoginRight用來是否打開驗證用戶登陸,這在咱們開發系統中調試後臺控制器頗有用;

 

2)Winform系統用戶驗證,這個比較簡單,用戶登陸後根據後臺配置的用戶權限,動態加載系統的菜單,因此後面的操做也不用再進行用戶驗證了;

 

3)WCF系統用戶驗證,就是上面兩種的結合了,客戶端如Winform系統,WCF中間件在WCFHandlerService服務中進行用戶驗證;

 

3.單點登陸樣例

用上面講過的Winform系統嵌入Web頁面這種狀況下如何使用單點登陸的功能;

在登陸成功後調用框架中的SsoHelper對象的SignIn方法生成TokenKey;

 

而後把TokenKey值加入Web頁面的URL地址以後,而後web頁面向後臺發送Ajax請求的時候把TokenKey當成參數傳入後臺,後臺進行單點登陸驗證。

 

 

 

4.單點登陸SSO實現代碼

框架源代碼目錄結構:

 

其中外部調用SSO功能只須要調用SsoHelper對象就能夠了,SsoHelper把SSO封裝成外部調用的類;包括SignIn、SignOut、ValidateToken等方法;TokenManager類存儲全部登陸用戶的信息,TokenInfo類封裝的用戶信息結構;
SsoHelper文件

  1 /// <summary>
  2     /// 單點登陸輔助類
  3     /// </summary>
  4     public class SsoHelper
  5     {        
  6         /// <summary>
  7         /// 登陸
  8         /// </summary>
  9         /// <param name="userId"></param>
 10         /// <param name="tokenid"></param>
 11         /// <returns></returns>
 12         public static bool SignIn(string userId,string userName, out Guid tokenid)
 13         {
 14             TokenInfo existToken = TokenManager.GetToken(userId);
 15             if (existToken != null)
 16             {
 17                 tokenid = existToken.tokenId;
 18                 return true;
 19             }
 20 
 21             TokenInfo token = new TokenInfo()
 22             {
 23                 tokenId = Guid.NewGuid(),
 24                 IsValid = true,
 25                 CreateTime = DateTime.Now,
 26                 ActivityTime=DateTime.Now,
 27                 UserId = userId,
 28                 UserName=userName//,
 29                 //RemoteIp = Utility.RemoteIp
 30             };
 31             tokenid = token.tokenId;
 32             return TokenManager.AddToken(token);
 33         }
 34         /// <summary>
 35         /// 註銷
 36         /// </summary>
 37         /// <param name="token"></param>
 38         /// <returns></returns>
 39         public static bool SignOut(Guid token)
 40         {
 41             return TokenManager.RemoveToken(token);
 42         }
 43         /// <summary>
 44         /// 是否有效登陸
 45         /// </summary>
 46         /// <param name="token"></param>
 47         /// <returns></returns>
 48         public static AuthResult ValidateToken(string token)
 49         {
 50             Guid guid= ConvertHelper.GetGuid(token, Guid.NewGuid());
 51 
 52             AuthResult result = new AuthResult() { ErrorMsg = "Token不存在" };
 53             TokenInfo existToken = TokenManager.GetToken(guid);
 54 
 55             if (existToken != null)
 56             {
 57                 #region 客戶端IP不一致
 58                 //if (existToken.RemoteIp != entity.RemoteIp)
 59                 //{
 60                 //    result.ErrorMsg = "客戶端IP不一致";
 61                 //}
 62                 #endregion
 63 
 64                 if (existToken.IsValid == false)
 65                 {
 66                     result.ErrorMsg = "Token已過時" + existToken.ActivityTime.ToLongTimeString() + ":" + DateTime.Now.ToLocalTime();
 67                     TokenManager.RemoveToken(existToken.tokenId);//移除
 68                 }
 69                 else  
 70                 {
 71                     result.User = new UserInfo() { UserId = existToken.UserId,UserName=existToken.UserName, CreateDate = existToken.CreateTime };
 72                     result.ErrorMsg = string.Empty;
 73                 }
 74             }
 75 
 76             return result;
 77         }
 78 
 79         /// <summary>
 80         /// 定時觸發登陸碼的活動時間,頻率必須小於4分鐘
 81         /// </summary>
 82         /// <param name="token"></param>
 83         public static void UserActivity(Guid token)
 84         {
 85             TokenInfo existToken = TokenManager.GetToken(token);
 86             existToken.ActivityTime = DateTime.Now;
 87         }
 88 
 89         /// <summary>
 90         /// 用戶是否在線
 91         /// </summary>
 92         /// <param name="userId"></param>
 93         /// <returns></returns>
 94         public static bool IsUserOnline(string userId)
 95         {
 96             TokenInfo existToken = TokenManager.GetToken(userId);
 97             if (existToken != null) return true;
 98             return false;
 99         }
100     }
View Code

TokenManager文件

 1  public class TokenManager
 2     {
 3         private const int _TimerPeriod = 60000;//60秒
 4         private static Timer thTimer;
 5 
 6         static List<TokenInfo> tokenList = null;
 7 
 8         static TokenManager()
 9         {
10             tokenList = new List<TokenInfo>();
11             thTimer = new Timer(_ThreadTimerCallback, null, _TimerPeriod, _TimerPeriod);
12         }
13 
14         public static bool AddToken(TokenInfo entity)
15         {
16             tokenList.Add(entity);
17             return true;
18         }
19 
20         public static bool RemoveToken(Guid token)
21         {
22             TokenInfo existToken = tokenList.SingleOrDefault(t => t.tokenId ==token);
23             if (existToken != null)
24             {
25                 tokenList.Remove(existToken);
26                 return true;
27             }
28 
29             return false;
30         }
31 
32         public static TokenInfo GetToken(Guid token)
33         {
34             TokenInfo existToken = tokenList.SingleOrDefault(t => t.tokenId == token);
35             return existToken;
36         }
37 
38         public static TokenInfo GetToken(string userId)
39         {
40             TokenInfo existToken = tokenList.SingleOrDefault(t => (t.UserId == userId && t.IsValid==true));
41             return existToken;
42         }
43 
44         private static void _ThreadTimerCallback(Object state)
45         {
46             DateTime now = DateTime.Now;
47 
48             Monitor.Enter(tokenList);
49             try
50             {
51                 // Searching for expired users
52                 foreach (TokenInfo t in tokenList)
53                 {
54                     if (((TimeSpan)(now - t.ActivityTime)).TotalMilliseconds > _TimerPeriod)
55                     {
56                         t.IsValid = false;//失效
57                     }
58                 }
59             }
60             finally
61             {
62                 Monitor.Exit(tokenList);
63             }
64         }
65     }
View Code

TokenInfo文件

 1  public class TokenInfo
 2     {
 3         public Guid tokenId { get; set; }
 4 
 5         public DateTime CreateTime { get; set; }
 6 
 7         public DateTime ActivityTime { get; set; }
 8 
 9         public string RemoteIp { get; set; }
10 
11         public string UserId { get; set; }
12 
13         public string UserName { get; set; }
14 
15         public bool IsValid { get; set; }
16     }
View Code

 

參考資料:

編寫你本身的單點登陸(SSO)服務

http://blog.csdn.net/javachannel/article/details/752437

相關文章
相關標籤/搜索