這篇文章介紹了.NET單點登陸的實現方法及思路,有需要的朋友可以參考一下,希望對你有所幫助
系統的基本架構
我們假設一個系統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站點,以方便我們在部署時方便修改。
復制代碼 代碼如下:
<appsettings>
<add key="Service" value="http://localhost:8001" />
<add key="WebSite" value="http://localhost:8002" />
</appsettings>
在Project類裡進行引用。
復制代碼 代碼如下:
using System;
using System.Configuration;
namespace Amethysture.SSO.Shop
{
public class Project
{
public static string Service = ConfigurationSettings.AppSettings["Service"];
public static string WebSite = ConfigurationSettings.AppSettings["WebSite"];
}
}
2、Shop的Global.cs
Shop的Global.cs定義了四個Session變量,UserID用來標識用 戶身份。Pass標識用戶即時狀態,Security用於保存往來Service和Shop的通訊不是被仿冒的。Url保存了上次請求的頁面,以保證在用 戶登錄後能轉到用戶請求的頁面。
復制代碼 代碼如下:
protected void Session_Start(Object sender, EventArgs e)
{
this.Session.Add("UserID", 0);
this.Session.Add("Pass", false);
this.Session.Add("Security", "");
this.Session.Add("Url", "");
}
3、Shop的Any.cs
Shop的Any.cs並沒有包含代碼,因為Any類從Page繼承而來,為了代碼分析方便,我們將代碼集中到Page.cs中。
復制代碼 代碼如下:
using System;
using System.Web;
namespace Amethysture.SSO.Shop
{
public class Any : Amethysture.SSO.Shop.Page
{
}
}
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應答的數據是沒有經過修改的。
復制代碼 代碼如下:
using System;
using System.Web;
using System.Security.Cryptography;
using System.Text;
namespace Amethysture.SSO.Shop
{
public class Page : System.Web.UI.Page
{
private void CustomerValidate()
{
bool Pass = (bool) this.Session["Pass"];
if (!Pass)
{
string Security = "";
Random Seed = new Random();
Security = Seed.Next(1, int.MaxValue).ToString();
byte[] Value;
UnicodeEncoding Code = new UnicodeEncoding();
byte[] Message = Code.GetBytes(Security);
SHA512Managed Arithmetic = new SHA512Managed();
Value = Arithmetic.ComputeHash(Message);
Security = "";
foreach(byte o in Value)
{
Security += (int) o + "O";
}
this.Session["Security"] = Security;
this.Session["Url"] = this.Request.RawUrl;
this.Response.Redirect(Project.Service + "/Validate.aspx?WebSite=" + Project.WebSite + "&Security=" + Security);
}
}
protected virtual void Initialize()
{
this.Response.Write("<html>");
this.Response.Write("<head>");
this.Response.Write("<title>Amethysture SSO Project</title>");
this.Response.Write("<link rel=stylesheet type="text/css" href="" + project.website + "/Default.css">");
this.Response.Write("</head>");
this.Response.Write("<body>");
this.Response.Write("<iframe width="0" height="0" src="" + project.service + "/Customer.aspx"></iframe>");
this.Response.Write("<div align="center">");
this.Response.Write("Amethysture SSO Shop Any Page");
this.Response.Write("</div>");
this.Response.Write("</body>");
this.Response.Write("</html>");
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.CustomerValidate();
this.Initialize();
this.Response.End();
}
}
}
5、Service的Global.cs
現在我們頁面轉到了Service的Validate頁面,我們轉過來看 Service的代碼。在Global中我們同樣定義了四個Session變量,都和Shop的Session用處類似。WebSite是保存請求用戶即 時狀態的站點信息。以便能在登錄後返回正確的請求站點。
復制代碼 代碼如下:
protected void Session_Start(Object sender, EventArgs e)
{
this.Session.Add("UserID", 0);
this.Session.Add("Pass", false);
this.Session.Add("WebSite", "");
this.Session.Add("Security", "");
}
6、Service的Validate.cs