採用集中式 Passport 驗證:一個主站負責帳號驗證與 Token 簽發,多個分站(子系統)透過 Token 向主站換取使用者憑證,並建立本地 Session 減少後續網路往返。
| 術語 | 定義 | 範例 |
|---|---|---|
| 主站 | 集中驗證服務 | https://www.passport.com/ |
| 分站 | 業務子系統 | https://www.a.com/、https://www.b.com/ |
| 憑證 | 使用者身份資料(主站用 Cache,分站用 Session) | UserId、Roles、DisplayName |
| Token | 跨域流通的唯一憑證,存於主站 Cookie(Domain=passport.com) | Guid.NewGuid().ToString() |
TokenGetCredence(token) 取得 UserInfo → 寫入本地 Session → 允許存取。
// 主站登入成功後
string token = Guid.NewGuid().ToString("N").ToUpper();
var cookie = new HttpCookie("Token") { Domain = "passport.com" };
cookie.Values["Value"] = token;
Response.AppendCookie(cookie);
// 同時寫入主站 Cache(Token → UserInfo)
Cache.Insert("CERT_" + token, userInfo, null,
DateTime.Now.AddMinutes(30), TimeSpan.Zero);
分站如何取得主站 Cookie?
導向主站 gettoken.aspx,該頁讀取 Cookie 並以 QueryString 回傳給分站。
private static void EnsureCache()
{
if (HttpContext.Current.Cache["CERT"] == null)
{
var dt = new DataTable();
dt.Columns.Add("token", typeof(string)).Unique = true;
dt.Columns.Add("info", typeof(object));
dt.Columns.Add("timeout", typeof(DateTime));
dt.PrimaryKey = new[] { dt.Columns["token"] };
HttpContext.Current.Cache.Insert("CERT", dt, null,
DateTime.MaxValue, TimeSpan.FromMinutes(60)); // 雙倍 Token 存活
}
}
public class AuthBase : Page
{
protected override void OnLoad(EventArgs e)
{
if (Session["Token"] != null) { base.OnLoad(e); return; } // 本地憑證存在
string token = Request.QueryString["Token"];
if (!string.IsNullOrEmpty(token) && token != "$Token$")
{
var svc = new TokenService();
object cred = svc.TokenGetCredence(token);
if (cred != null)
{
Session["Token"] = cred; // 建立本地憑證
base.OnLoad(e);
return;
}
}
// 導向主站登入或重新取 Token
Response.Redirect(token == "$Token$" ? GetLoginUrl() : GetTokenUrl());
}
private string GetTokenUrl()
{
string url = Request.Url.AbsoluteUri;
url += url.Contains("?") ? "&Token=$Token$" : "?Token=$Token$";
return "https://www.passport.com/gettoken.aspx?BackUrl=" + Server.UrlEncode(url);
}
private string GetLoginUrl() { /* 類似,導向 userlogin.aspx */ }
}
所有需驗證的分站頁面僅需繼承 AuthBase 即可自動擁有 SSO 能力。
| 面向 | 建議 |
|---|---|
| Token 傳輸 | 全站強制 HTTPS,防止 Token 被竊聽重放。 |
| Token 有效期 | 短效(15-30 分鐘)+ Sliding Expiration,平衡安全與體驗。 |
| 跨域 Cookie | 若主站與分站非同根域,需 P3P 標頭或改用 OAuth2/OpenID Connect 標準流程。 |
| 高可用 | 主站 Cache 改用 Redis Cluster / SQL Server Session State,支援多節點。 |
| 防 CSRF | Token 簽發時綁定 User-Agent / IP 指紋,驗證時比對。 |