数日前、友人からシングル サインオンについて手伝ってほしいと頼まれました。実際、この概念は以前からよく知られていましたが、最近は実際に使えるアプリケーションがほとんどないので、SSO ソリューションについて説明することにしました。この記事を通じて詳しく説明しますので、皆さんのお役に立てれば幸いです。 SSO ソリューションは数多くありますが、検索結果は残念なものが多く、それらのほとんどは相互に再投稿されており、説明は表面的です。
おしゃべりはこれくらいにして、本題に入りましょう。私のアイデアは、複数のサイトで一元的な認証方法と一元的なパスポート認証を使用することです。 以下の図に示すように:
明確な説明を容易にするために、この記事に登場するすべての名詞は次のような意味を持ちます。
メインサイト: パスポート集中認証サーバー http://www.passport.com/。
ブランチ: http://www.a.com/、http://www.b.com/、http://www.c.com/
認証情報: ユーザーのログイン後に生成され、識別に使用されるデータ識別承認されたユーザーにはさまざまな方法があります。デモでは、メイン サイトにはキャッシュを使用し、サブサイトにはセッションを使用します。
トークン: パスポートによって発行され、各支店で流通できる一意の識別子。
OK、シングル サインオン プロセスについて説明します。
シナリオ 1. 匿名ユーザー: 匿名ユーザーは、サブサイト a の認証ページにアクセスします。まず、メイン サイトにジャンプし、ユーザーが自分のアカウント番号とパスワードを入力できるようにします。検証に合格すると、メイン サイトの資格情報は同時にトークンを生成し、サブステーション a に戻ります。このとき、サブステーション a はユーザーがすでにトークンを保持していることを検出し、そのトークンを使用します。メイン サイトに再度アクセスしてユーザー資格情報を取得します。取得が成功すると、ユーザーは認証ページにアクセスできるようになります。同時に、ブランチ a のローカル資格情報が生成され、ユーザーを再度認証する必要がある場合、ネットワークのやり取りを減らすために、最初にローカル資格情報がチェックされます。
シナリオ 2: サブサイト a にログインしたユーザーがサブサイト b にアクセスします: ユーザーはサブサイト a にログインしており、すでにトークンを保持しているため、サブサイト b はそのトークンを使用してメイン サイトに移動しますユーザーの認証情報を取得するため、取得に成功すると、ユーザーのアクセス許可ページが許可されます。同時に、変電所 b のローカル資格情報が生成されます。
設計が完了したら、ソリューションを実装するための重要なポイントをいくつか示します。
トークン: メイン ステーションによってトークンが発行され、同時にユーザーの資格情報が生成されます。 、トークンとユーザー資格情報の関係を記録します。対応する関係は、ユーザーが提供したトークンに基づいて対応する資格情報に応答することです。そのため、トークンは各クロスドメイン ブランチで循環される必要があります。 DEMO トークン内のメイン サイトに Cookie.Domain="passport.com " を指定します。各ブランチ サイトはメイン サイトの Cookie をどのように共有しますか?サブサイトからメイン サイトのページにリダイレクトすると、ページは Cookie を読み取り、それを URL パラメーターの形式で送り返します。もちろん、より適切なトークンを持っている人がいる場合は、詳細な実装を確認できます。実装したら共有してください。
//产生令牌 string tokenValue = Guid.NewGuid().ToString().ToUpper(); HttpCookie tokenCookie = new HttpCookie("Token"); tokenCookie.Values.Add("Value", tokenValue); tokenCookie.Domain = "passport.com"; Response.AppendCookie(tokenCookie);
メイン サイトの証明書: メイン サイトの証明書は、トークン、証明書データ、有効期限の 3 つのフィールドを含むリレーショナル テーブルです。実装方法は多数ありますが、信頼性が必要な場合はデータベースを使用し、デモでは Cache の DataTable を使用しました。次のコードに示すように:
/// <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)); } }
サブサイトの資格情報: サブサイトの資格情報は、主に検証を繰り返す際のネットワーク インタラクションを減らすために使用されます。たとえば、ユーザーがサブサイト a にログインしたとします。再度、a はコマンドを使用する必要はありません。サブサイト A はすでにユーザーの資格情報を持っているため、カードは検証のためにメイン サイトに送信されました。サブサイトの認証情報は比較的単純で、セッションまたは Cookie を使用できます。
サブサイトSSOページの基本クラス: サブサイト内でSSOを利用するページは、記事冒頭のフローチャートのような一連の論理的な判断処理を行います。複数のページがある場合、ページごとにそのようなロジックを記述することは不可能です。このロジックのセットを基本クラスにカプセル化すると、SSO を使用するすべてのページがこの基本クラスを継承できます。次のコードに示すように:
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 }
ユーザー終了: ユーザーが終了すると、メイン サイトの資格情報と現在のサブサイトの資格情報がそれぞれクリアされます。サイト A を終了する必要があり、サイト B および C も終了する場合は、インターフェイスを拡張して各サブステーションの資格情報をクリアできます。
メイン サイトの期限切れの資格情報/トークンをクリアします。(DataTable) Cache["CERT"] のタイムアウト フィールドが現在時刻を超えているレコードを定期的にクリアします。
.Net に基づくシングル サインオン (SSO) 実装ソリューションに関連するその他の記事については、PHP 中国語 Web サイトに注目してください。