Vor ein paar Tagen hat mich ein Freund gebeten, beim Single Sign-On zu helfen. Tatsächlich ist dieses Konzept schon lange bekannt, aber es gibt in letzter Zeit nur wenige praktische Anwendungen, daher habe ich beschlossen, es zu beschreiben Ich hoffe, dass die SSO-Lösung für alle hilfreich ist. Es gibt viele SSO-Lösungen, aber die Suchergebnisse sind enttäuschend. Die meisten davon sind voneinander repostet und auch die Beschreibungen sind oberflächlich.
Kommen wir ohne weitere Umschweife zum Punkt. Meine Idee ist, eine zentrale Verifizierung und eine zentrale Passüberprüfung auf mehreren Websites zu verwenden. Wie in der folgenden Abbildung dargestellt:
Um eine klare Beschreibung zu erleichtern, definieren wir zunächst einige Substantive. Die in diesem Artikel vorkommenden Bedeutungen sind wie folgt.
Hauptseite: Zentraler Passport-Verifizierungsserver http://www.passport.com/.
Zweigstellen: http://www.a.com/, http://www.b.com/, http://www.c.com/
Anmeldeinformationen: Datenidentifikation, die nach der Benutzeranmeldung generiert wird. Wird zur Identifizierung autorisierter Benutzer verwendet und kann auf verschiedene Arten verwendet werden. In der DEMO verwende ich Cache für die Hauptseite und Sitzung für die Unterseiten.
Token: Eine von Passport ausgegebene eindeutige Kennung, die in jeder Filiale weitergegeben werden kann.
OK, beschreiben Sie nun den Single-Sign-On-Prozess:
Szenario 1. Anonymer Benutzer: Ein anonymer Benutzer greift auf eine Autorisierungsseite auf der Unterseite a zu. Zuerst springt er zur Hauptseite und ermöglicht dem Benutzer den Zugriff Geben Sie Ihre Kontonummer und Ihr Passwort ein, um sich anzumelden. Nach bestandener Überprüfung werden die Anmeldeinformationen für den Hauptstandort generiert, und gleichzeitig wird das Token generiert und zu Unterstandort a zurückgesprungen. Zu diesem Zeitpunkt erkennt die Unterstation a Der Benutzer verfügt bereits über das Token, sodass er mit dem Token erneut zur Hauptseite gehen und die Benutzeranmeldeinformationen abrufen kann. Nach erfolgreicher Erfassung ist es möglich, dass der Benutzer auf die Autorisierungsseite zugreift. Gleichzeitig werden die lokalen Anmeldeinformationen von Zweig a generiert. Wenn der Benutzer erneut authentifiziert werden muss, werden zuerst die lokalen Anmeldeinformationen überprüft, um die Netzwerkinteraktion zu reduzieren.
Szenario 2: Ein auf der Unterseite a angemeldeter Benutzer besucht die Unterseite b: Da sich der Benutzer auf der Unterseite a angemeldet hat und bereits über ein Token verfügt, verwendet Unterseite b das Token, um zur zu gelangen Hauptseite, um die Benutzeranmeldeinformationen zu erhalten, und der Erwerb ist erfolgreich. Der Benutzer darf dann auf die Autorisierungsseite zugreifen. Gleichzeitig werden die lokalen Zugangsdaten der Unterstation b generiert.
Nach Abschluss des Entwurfs sind hier einige wichtige Punkte der Lösungsimplementierung:
Token: Der Token wird von der Hauptstation ausgegeben und die Hauptstation gibt sie aus Das Token generiert gleichzeitig Benutzeranmeldeinformationen und zeichnet die Korrespondenz zwischen Token und Benutzeranmeldeinformationen auf, um auf die entsprechenden Anmeldeinformationen basierend auf dem vom Benutzer bereitgestellten Token zu reagieren. Daher müssen Token in verschiedenen domänenübergreifenden Unterstationen verteilt werden Ich verwende im DEMO-Cookie den Token des Hauptbahnhofs und gebe Cookie.Domain="passport.com" an. Wie teilen die einzelnen Filialstandorte die Cookies der Hauptstandorte? Leiten Sie von der Unterseite zur Hauptseite weiter, und dann liest die Seite das Cookie und sendet es in Form von URL-Parametern zurück. Wenn jemand ein besseres Token hat, können Sie sich die detaillierte Implementierung natürlich ansehen Umsetzung, bitte teilen.
//产生令牌 string tokenValue = Guid.NewGuid().ToString().ToUpper(); HttpCookie tokenCookie = new HttpCookie("Token"); tokenCookie.Values.Add("Value", tokenValue); tokenCookie.Domain = "passport.com"; Response.AppendCookie(tokenCookie);
Anmeldeinformationen für die Hauptseite: Die Anmeldeinformationen für die Hauptseite sind eine relationale Tabelle, die drei Felder enthält: Token, Anmeldedaten und Ablaufzeit. Es stehen viele Implementierungsmethoden zur Auswahl. Wenn Zuverlässigkeit erforderlich ist, verwenden Sie den Cache. Wie im folgenden Code gezeigt:
/// <summary> /// 初始化数据结构 /// </summary> /// <remarks> /// ---------------------------------------------------- /// | token(令牌) | info(用户凭证) | timeout(过期时间) | /// |--------------------------------------------------| /// </remarks> private static void cacheInit() { if (HttpContext.Current.Cache["CERT"] == null) { DataTable dt = new DataTable(); dt.Columns.Add("token", Type.GetType("System.String")); dt.Columns["token"].Unique = true; dt.Columns.Add("info", Type.GetType("System.Object")); dt.Columns["info"].DefaultValue = null; dt.Columns.Add("timeout", Type.GetType("System.DateTime")); dt.Columns["timeout"].DefaultValue = DateTime.Now.AddMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"])); DataColumn[] keys = new DataColumn[1]; keys[0] = dt.Columns["token"]; dt.PrimaryKey = keys; //Cache的过期时间为 令牌过期时间*2 HttpContext.Current.Cache.Insert("CERT", dt, null, DateTime.MaxValue, TimeSpan.FromMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"]) * 2)); } }
Subsite-Anmeldeinformationen: Subsite-Anmeldeinformationen werden hauptsächlich verwendet, um die Netzwerkinteraktion bei wiederholter Überprüfung zu reduzieren. Beispielsweise hat sich der Benutzer bei Subsite a angemeldet. und wenn er die Unterseite a erneut besucht, besteht keine Notwendigkeit, das Token zu verwenden, um zur Überprüfung zur Hauptseite zu gelangen, da Zweig a bereits über die Anmeldeinformationen des Benutzers verfügt. Die Anmeldeinformationen für die Unterseite sind relativ einfach und können Sitzung oder Cookie verwenden.
Basisklasse der SSO-Seite der Unterseite: Die Seite der Unterseite, die SSO verwendet, führt eine Reihe logischer Beurteilungsverarbeitungen durch, wie zum Beispiel das Flussdiagramm am Anfang des Artikels. Wenn es mehrere Seiten gibt, ist es nicht möglich, eine solche Logik für jede Seite zu schreiben. Dann kapseln Sie diese Logik in eine Basisklasse, und alle Seiten, die SSO verwenden möchten, können diese Basisklasse erben. Wie im folgenden Code gezeigt:
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Text.RegularExpressions; namespace SSO.SiteA.Class { /// <summary> /// 授权页面基类 /// </summary> public class AuthBase : System.Web.UI.Page { protected override void OnLoad(EventArgs e) { if (Session["Token"] != null) { //分站凭证存在 Response.Write("恭喜,分站凭证存在,您被授权访问该页面!"); } else { //令牌验证结果 if (Request.QueryString["Token"] != null) { if (Request.QueryString["Token"] != "$Token$") { //持有令牌 string tokenValue = Request.QueryString["Token"]; //调用WebService获取主站凭证 SSO.SiteA.RefPassport.TokenService tokenService = new SSO.SiteA.RefPassport.TokenService(); object o = tokenService.TokenGetCredence(tokenValue); if (o != null) { //令牌正确 Session["Token"] = o; Response.Write("恭喜,令牌存在,您被授权访问该页面!"); } else { //令牌错误 Response.Redirect(this.replaceToken()); } } else { //未持有令牌 Response.Redirect(this.replaceToken()); } } //未进行令牌验证,去主站验证 else { Response.Redirect(this.getTokenURL()); } } base.OnLoad(e); } /// <summary> /// 获取带令牌请求的URL /// 在当前URL中附加上令牌请求参数 /// </summary> /// <returns></returns> private string getTokenURL() { string url = Request.Url.AbsoluteUri; Regex reg = new Regex(@"^.*\?.+=.+$"); if (reg.IsMatch(url)) url += "&Token=$Token$"; else url += "?Token=$Token$"; return "http://www.passport.com/gettoken.aspx?BackURL=" + Server.UrlEncode(url); } /// <summary> /// 去掉URL中的令牌 /// 在当前URL中去掉令牌参数 /// </summary> /// <returns></returns> private string replaceToken() { string url = Request.Url.AbsoluteUri; url = Regex.Replace(url, @"(\?|&)Token=.*", "", RegexOptions.IgnoreCase); return "http://www.passport.com/userlogin.aspx?BackURL=" + Server.UrlEncode(url); } }//end class }
Benutzerausgang: Wenn der Benutzer beendet, werden die Anmeldeinformationen der Hauptseite bzw. die Anmeldeinformationen der aktuellen Unterseite gelöscht. Wenn Standort A beendet werden muss und die Standorte B und C ebenfalls beendet werden, können Sie die Schnittstelle erweitern, um die Anmeldeinformationen jeder Unterstation zu löschen.
Löschen Sie die abgelaufenen Anmeldeinformationen/Tokens der Hauptseite: Löschen Sie regelmäßig die Datensätze, deren Timeout-Feld im (DataTable) Cache["CERT"] die aktuelle Zeit überschreitet.
Weitere Artikel zu Single Sign-On (SSO)-Implementierungslösungen auf Basis von .Net finden Sie auf der chinesischen PHP-Website!