911亚洲精品视频-亚洲日本在线看片-摸胸软件-三级**毛片|www.szkangyu.net

E-Mail:115294781@qq.com 聯系電話: 020-84226565

單點登陸.NET的簡單實現 (轉)

2013-10-24

系統的基本架構

   我們假設一個系統System包含Service客戶服務中心、Shop網上購物中心和Office網上辦公中心三個獨立的網站。 Service管理客戶的資料,登錄和注銷過程。不論客戶訪問System的任何一個頁面,系統都會轉到登錄界面,在用戶登錄后,系統會自動轉會到客戶上 次請求的頁面。并且用戶此后可以在System中無縫切換。不需要再次進行登錄。即在System中實現單點登錄SSO(Single Sign-On)。

  我們知道,用戶的即時狀態通常是使用Application、Session、Cookie和存儲的。而這些都是不能在程序中跨站點訪問的。我們必需通過站點間相互通訊來確認用戶的即時狀態。

 

 簡單的實現

 

   第一步,假設用戶訪問了Shop或Office的任何一個頁面Any。該頁面所在的網站將會檢查用戶的即時狀態。如果用戶已經登錄了,則將 Any頁面的信息返回給用戶。如果用戶還沒有登錄,則自動轉到Service的Validate頁面,驗證用戶在Service狀態。即Shop或 Office向Service發出請求,要求Service返回用戶的即時狀態。

  第二步,Validate驗證用戶的即時狀態,如果 用戶已經登錄了,則Service將用戶的即時狀態返回給Shop或Office的同步頁面 Synchronous,通知Shop或Office同步用戶狀態。如果用戶沒有登錄,則自動轉向Customer頁面,提示用戶登錄。

  第三步,用戶完成登錄過程,當用戶成功登錄后,自動轉回Validate頁面,通知Shop或Office的Synchronous進行用戶狀態的同步。

  第四步,在用戶狀態同步完成后,在本地站點,用戶狀態成為在線狀態,即可訪問Any頁面。

  在上面的流程中。我們知道,不管用戶訪問哪個站點,用戶只需要一次登錄,就保證用戶在Service的即時狀態都是在線的,不會再需要進行第二次登錄的過程。

  現在我們的思路已經清楚,具體的實現我們將在代碼分析中完成。

 

代碼分析

  從上面的流程中我們可以看出,系統中Shop和Office的代碼是完全類似的。只要Shop可以實現,Office也可以同樣的克隆。所以我們的重點分析的對象是Shop和Service的代碼。



  1、Shop的Web.config和Project.cs

  在Shop的Web.config里,我們配置了Service站點和Shop站點,以方便我們在部署時方便修改。


 

  1. <appsettings>
  2. <add key="Service" value="http://localhost:8001" />
  3. <add key="WebSite" value="http://localhost:8002" />
  4. </appsettings> 

  5.  

  在Project類里進行引用。


 

  1. using System;
  2. using System.Configuration;

  3.  
  4. namespace Amethysture.SSO.Shop
  5. {
  6.  public class Project
  7.  {
  8.   public static string Service = ConfigurationSettings.AppSettings["Service"];
  9.   public static string WebSite = ConfigurationSettings.AppSettings["WebSite"];
  10.  }
  11. }

  2、Shop的Global.cs

   Shop的Global.cs定義了四個Session變量,UserID用來標識用 戶身份。Pass標識用戶即時狀態,Security用于保存往來Service和Shop的通訊不是被仿冒的。Url保存了上次請求的頁面,以保證在用 戶登錄后能轉到用戶請求的頁面。


 

  1. protected void Session_Start(Object sender, EventArgs e)
  2. {
  3.  this.Session.Add("UserID", 0);
  4.  this.Session.Add("Pass", false);
  5.  this.Session.Add("Security", "");
  6.  this.Session.Add("Url", "");
  7. }

  3、Shop的Any.cs

  Shop的Any.cs并沒有包含代碼,因為Any類從Page繼承而來,為了代碼分析方便,我們將代碼集中到Page.cs中。

 

  1. using System;
  2. using System.Web;

  3.  
  4. namespace Amethysture.SSO.Shop
  5. {
  6.  public class Any : Amethysture.SSO.Shop.Page
  7.  {
  8.  }
  9. }

  4、Shop的Page.cs

  Page類有兩個方法,CustomerValidate和Initialize。CustomerValidate用戶檢查用戶的即時狀態,而Initialize是頁面登錄后發送給用戶的信息。我們的重點是CustomerValidate。

   CustomerValidate是一個非常簡單的流程,用條件語句檢查Pass的狀態,如果Pass為否,則表示用戶沒有登錄,頁面跳轉到 Service的Validate頁面中。我們要分析的是其中保存的Url和遞交的WebSite和Security幾個參數。Url的作用在前面已經講 清楚了,只是為了保證用戶登錄后能回到原來的頁面。而WebSite是為了保證該站點是被Service所接受的,并且保證Service知道是哪個站點 請求了用戶即時狀態。因為這個例子是個簡單的例子,在后面的Validate里沒有驗證WebSite是否是接受的請求站點,但是在實際應用中應該驗證這 一點,因為Shop和Service等同于服務器和客戶端,服務器出于安全考慮必須要檢查客戶端是否是被允許的。Security是非常重要的一點。 Shop對Service發送的是請求,不需要保證該請求沒有被篡改,但是在Service應答Shop請求時就必須要保證應答的數據沒有被篡改了。 Security正是為了保證數據安全而設計的。

  在代碼中,Security是通過Hash一個隨機產生的數字生成的。具有不確定 性。和保密性。我們可以看到,Security同時保存在Session中和發送給Service。我們把這個Security當作明文。在后面我們可以 看到,Security在Service經過再一次Hash后作為密文發送回Shop。如果我們將Session保存的Security經過同樣的 Hash方法處理后等到的字符串如果和Service返回的密文相同,我們就能夠在一定程度上保證Service應答的數據是沒有經過修改的。

 

  1. using System;
  2. using System.Web;
  3. using System.Security.Cryptography;
  4. using System.Text;

  5.  
  6. namespace Amethysture.SSO.Shop
  7. {
  8.  public class Page : System.Web.UI.Page
  9.  {
  10.   private void CustomerValidate()
  11.   {
  12.    bool Pass = (bool) this.Session["Pass"];
  13.    if (!Pass)
  14.    {
  15.     string Security = "";
  16.     Random Seed = new Random();
  17.     Security = Seed.Next(1, int.MaxValue).ToString();
  18.     byte[] Value;
  19.     UnicodeEncoding Code = new UnicodeEncoding();
  20.     byte[] Message = Code.GetBytes(Security);
  21.     SHA512Managed Arithmetic = new SHA512Managed();
  22.     Value = Arithmetic.ComputeHash(Message);
  23.     Security = "";
  24.     foreach(byte o in Value)
  25.     {
  26.      Security += (int) o + "O";
  27.     }
  28.     this.Session["Security"] = Security;
  29.     this.Session["Url"] = this.Request.RawUrl;
  30.     this.Response.Redirect(Project.Service + "/Validate.aspx?WebSite=" + Project.WebSite + "&Security=" + Security);
  31.    }
  32.   }

  33.  
  34.   protected virtual void Initialize()
  35.   {
  36.    this.Response.Write("<html>");
  37.    this.Response.Write("<head>"); 
  38.    this.Response.Write("<title>Amethysture SSO Project</title>");
  39.    this.Response.Write("<link rel=stylesheet type=\"text/css\" href=\"" + project.website + "/Default.css\">");
  40.    this.Response.Write("</head>");
  41.    this.Response.Write("<body>");
  42.    this.Response.Write("<iframe width=\"0\" height=\"0\" src=\"" + project.service + "/Customer.aspx\"></iframe>");
  43.    this.Response.Write("<div align=\"center\">");
  44.    this.Response.Write("Amethysture SSO Shop Any Page");
  45.    this.Response.Write("</div>");
  46.    this.Response.Write("</body>");
  47.    this.Response.Write("</html>");
  48.   }

  49.  
  50.   protected override void OnInit(EventArgs e)
  51.   {
  52.    base.OnInit(e);
  53.    this.CustomerValidate();
  54.    this.Initialize();
  55.    this.Response.End();
  56.   }
  57.  }
  58. }

5、Service的Global.cs

   現在我們頁面轉到了Service的Validate頁面,我們轉過來看 Service的代碼。在Global中我們同樣定義了四個Session變量,都和Shop的Session用處類似。WebSite是保存請求用戶即 時狀態的站點信息。以便能在登錄后返回正確的請求站點。
 


 

  1. protected void Session_Start(Object sender, EventArgs e)
  2. {
  3.  this.Session.Add("UserID", 0);
  4.  this.Session.Add("Pass", false);
  5.  this.Session.Add("WebSite", "");
  6.  this.Session.Add("Security", "");
  7. }

  6、Service的Validate.cs

  首先,將Shop傳遞過來的參數保存到Session中。如果用戶沒有登錄,則轉到Customer頁面進行登錄。如果用戶已經登錄了。則將用戶即時狀態傳回給Shop站點。如上所述,這里將Security重新Hash了一次傳回給Shop,以保證數據不被纂改。

 

 


 

  1. private void CustomerValidate()
  2. {
  3.  bool Pass = (bool) this.Session["Pass"];
  4.  if ((this.Request.QueryString["WebSite"] != null) && (this.Request.QueryString["WebSite"] != ""))
  5.  {
  6.   this.Session["WebSite"] = this.Request.QueryString["WebSite"];
  7.  }
  8.  if ((this.Request.QueryString["Security"] != null) && (this.Request.QueryString["Security"] != ""))
  9.  {
  10.   this.Session["Security"] = this.Request.QueryString["Security"];
  11.  }
  12.  if (Pass)
  13.  {
  14.   string UserID = this.Session["UserID"].ToString();
  15.   string WebSite = this.Session["WebSite"].ToString();
  16.   string Security = this.Session["Security"].ToString();
  17.   byte[] Value;
  18.   UnicodeEncoding Code = new UnicodeEncoding();
  19.   byte[] Message = Code.GetBytes(Security);
  20.   SHA512Managed Arithmetic = new SHA512Managed();
  21.   Value = Arithmetic.ComputeHash(Message);
  22.   Security = "";
  23.   foreach(byte o in Value)
  24.   {
  25.    Security += (int) o + "O";
  26.   }
  27.   this.Response.Redirect(WebSite + "/Synchronous.aspx?UserID=" + UserID + "&Pass=True&Security=" + Security);
  28.  }
  29.  else
  30.  {
  31.   this.Response.Redirect("Customer.aspx");
  32.  }
  33. }

  7、Service的Customer.cs和Login.cs

   Customer主要的是一個用于登錄的表單,這里就不 貼出代碼了。這里分析一下Login的一段代碼,這段代碼是當登錄是直接在Service完成的(WebSite為空值),則頁面不會轉到Shop或 Office站點。所以應該暫停在Service站點。系統如果比較完美,這里應該顯示一組字系統的轉向鏈接。下面我們看到,當Pass為真時,頁面轉回 到Validate頁面,通過上面的分析,我們知道,頁面會轉向Shop的Synchronous頁面,進行用戶狀態的同步。

 

 


 

  1. if (Pass)
  2. {
  3.  if ((this.Session["WebSite"].ToString() != "") && (this.Session["Security"].ToString() != ""))
  4.  {
  5.   this.Response.Redirect("Validate.aspx");
  6.  }
  7.  else
  8.  {
  9.   this.Response.Write("");
  10.   this.Response.Write(""); 
  11.   this.Response.Write("");
  12.   this.Response.Write("");
  13.   this.Response.Write("");
  14.   this.Response.Write("");
  15.   this.Response.Write("");
  16.   this.Response.Write("Pass");
  17.   this.Response.Write("");
  18.   this.Response.Write("");  
  19.   this.Response.Write("");
  20.  }
  21. }
  22. else
  23. {
  24.  this.Response.Redirect("Customer.aspx");
  25. }

  8、Shop的Synchronous.cs

   好了,我們在Service中完成了登錄,并把用戶狀態傳遞回Shop站 點。我們接著看用戶狀態是怎么同步的。首先,如果Session里的Security是空字符串,則表示Shop站點沒有向Service發送過請求,而 Service向Shop發回了請求,這顯然是錯誤的。這次訪問是由客戶端偽造進行的訪問,于是訪問被拒絕了。同樣Security和 InSecurity不相同,則表示請求和應答是不匹配的。可能應答被纂改過了,所以應答同樣被拒絕了。當檢驗Security通過后,我們保證 Serive完成了應答,并且返回了確切的參數,下面就是讀出參數同步Shop站點和Service站點的用戶即時狀態。

 

 


 

  1. string InUserID = this.Request.QueryString["UserID"];
  2. string InPass = this.Request.QueryString["Pass"];
  3. string InSecurity = this.Request.QueryString["Security"];

  4.  
  5. string Security = this.Session["Security"].ToString();
  6. if (Security != "")
  7. {
  8.  byte[] Value;
  9.  UnicodeEncoding Code = new UnicodeEncoding();
  10.  byte[] Message = Code.GetBytes(Security);
  11.  SHA512Managed Arithmetic = new SHA512Managed();
  12.  Value = Arithmetic.ComputeHash(Message);
  13.  Security = "";
  14.  foreach(byte o in Value)
  15.  {
  16.   Security += (int) o + "O";
  17.  }

  18.  
  19.  if (Security == InSecurity)
  20.  {
  21.   if (InPass == "True")
  22.   {
  23.    this.Session["UserID"] = int.Parse(InUserID);
  24.    this.Session["Pass"] = true;
  25.    this.Response.Redirect(this.Session["Url"].ToString());
  26.   }
  27.  }
  28.  else
  29.  {
  30.   this.Response.Write("");
  31.   this.Response.Write(""); 
  32.   this.Response.Write("");
  33.   this.Response.Write("");
  34.   this.Response.Write("");
  35.   this.Response.Write("");
  36.   this.Response.Write("");
  37.   this.Response.Write("數據錯誤");
  38.   this.Response.Write("");
  39.   this.Response.Write("");
  40.   this.Response.Write("");
  41.  }
  42. }
  43. else
  44. {
  45.  this.Response.Write("");
  46.  this.Response.Write(""); 
  47.  this.Response.Write("");
  48.  this.Response.Write("");
  49.  this.Response.Write("");
  50.  this.Response.Write("");
  51.  this.Response.Write("");
  52.  this.Response.Write("訪問錯誤");
  53.  this.Response.Write("");
  54.  this.Response.Write("");
  55.  this.Response.Write("");
  56. }

  9、Shop的Page.cs

   我們知道,頁面在一段時間不刷新后,Session會超時失效,在我們一直訪問Shop的 時候怎么才能保證Service的Session不會失效呢?很簡單,我們返回來看Shop的Page.cs。通過在所有Shop的頁面內都用 <iframe>嵌套Service的某個頁面,就能保證Service能和Shop的頁面同時刷新。需要注意的一點是Service的Session必 須保證不小于所有Shop和Office的Session超時時間。這個在Web.config里可以進行配置。

 

 


 

  1. this.Response.Write("<iframe width=\"0\" height=\"0\" src=\"" + project.service + "/Customer.aspx\"></iframe>");

  總結

   一次完整的登錄完成了。我們接著假設一下現在要跳到Office的Any頁面,系統會進行怎樣的操作 呢?Any(用戶沒有登錄)->Validate(用戶已經登錄)->Synchronous(同步)->Any。也就是說這次,用戶沒有進行登錄的過 程。我們通過一次登錄,使得Service的用戶狀態為登錄,并且不管有多少個網站應用,只要這些網站都保證符合Shop的特性,這些網站就都能保持 Service的用戶狀態,同時能通過Service獲得用戶的狀態。也就是說我們實現了SSO。