ホームページ バックエンド開発 C#.Net チュートリアル ASP.NET MVC SSOシングルサインオン設計例の詳細説明

ASP.NET MVC SSOシングルサインオン設計例の詳細説明

Jul 03, 2017 pm 05:28 PM
asp.net ログイン デザイン

この記事では主に ASP.NET MVC SSO シングル サインオンの設計と実装について紹介します。興味がある方は詳細をご覧ください。

実験環境の構成

HOSTファイルの構成は次のとおりです:

127.0.0.1 app.com
127.0.0.1 sso.com

IISの構成は次のとおりです:

プールで使用する.Net Framework 4. 0

IIS にバインドされているドメイン名に注意してください。これは 2 つの完全に異なるドメイン名です。

app.com Web サイトの構成は次のとおりです:

sso.com Web サイトの構成は次のとおりです:

memcached キャッシュ:

データベース構成:

データベースは EntityFramework 6.0.0 を使用しており、対応するデータベースとテーブル構造は最初の実行時に自動的に作成されます。

認証検証プロセスのデモ:

ブラウザのアドレスバーで http://app.com にアクセスします。ユーザーがログインしていない場合、Web サイトは自動的に http://sso.com/passport にリダイレクトされます。同時に、QueryString パラメータを通じて対応する AppKey アプリケーション ID を渡します。実行中のスクリーンショットは次のとおりです。ログインアカウントとパスワードを入力した後、ログインボタンをクリックすると、システムは自動的にアプリケーションに 301 リダイレクトし、破壊が成功すると、次のようになります。

SSO 認証ログインなので。異なるドメインで実行される場合、QueryString メソッドを使用して認証 ID が返されます。 Cookie は同じドメインの Web サイトで使用できます。 301リダイレクトリクエストはブラウザから送信されるため、Handersに認可識別子を置くとブラウザがリダイレクトする際に認可識別子が失われます。リダイレクトが成功すると、プログラムは自動的に認証マークを Cookie に書き込み、別のページのアドレスをクリックすると、URL アドレス バーに認証マークの情報が表示されなくなります。 Cookieの設定は以下の通りです:

ログイン成功後の認証検証(認証が必要な他のページへのアクセス):

認証アドレス: http://sso.com/api/passport?

session

key=xxxxxx&remark =xxxxxx

戻り結果: true、false

クライアントは、実際のビジネス状況に基づいて、認証が失われ、再認証が必要であることをユーザーに通知するかどうかを選択できます。デフォルトでは、SSO ログイン ページ (http://sso.com/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&username=seo@ljja.cn) に自動的にリダイレクトされます。同時に、ログイン ページの電子メール アドレス テキスト ボックスが表示されます。ユーザーはログイン パスワードを入力するだけで、認証に成功すると、セッションの有効期間が自動的に 1 年間延長されます。

SSO データベース検証ログ:

ユーザー認可検証ログ:

ユーザー認可セッションセッション:

データベースユーザーアカウントとアプリケーション情報:

アプリケーション認可ログイン検証ページコアコード:

/// <summary>
  /// 公钥:AppKey
  /// 私钥:AppSecret
  /// 会话:SessionKey
  /// </summary>
  public class PassportController : Controller
  {
    private readonly IAppInfoService _appInfoService = new AppInfoService();
    private readonly IAppUserService _appUserService = new AppUserService();
    private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService();
    private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService();

    private const string AppInfo = "AppInfo";
    private const string SessionKey = "SessionKey";
    private const string SessionUserName = "SessionUserName";

    //默认登录界面
    public ActionResult Index(string appKey = "", string username = "")
    {
      TempData[AppInfo] = _appInfoService.Get(appKey);

      var viewModel = new PassportLoginRequest
      {
        AppKey = appKey,
        UserName = username
      };

      return View(viewModel);
    }

    //授权登录
    [HttpPost]
    public ActionResult Index(PassportLoginRequest model)
    {
      //获取应用信息
      var appInfo = _appInfoService.Get(model.AppKey);
      if (appInfo == null)
      {
        //应用不存在
        return View(model);
      }

      TempData[AppInfo] = appInfo;

      if (ModelState.IsValid == false)
      {
        //实体验证失败
        return View(model);
      }

      //过滤字段无效字符
      model.Trim();

      //获取用户信息
      var userInfo = _appUserService.Get(model.UserName);
      if (userInfo == null)
      {
        //用户不存在
        return View(model);
      }

      if (userInfo.UserPwd != model.Password.ToMd5())
      {
        //密码不正确
        return View(model);
      }

      //获取当前未到期的Session
      var currentSession = _authSessionService.ExistsByValid(appInfo.AppKey, userInfo.UserName);
      if (currentSession == null)
      {
        //构建Session
        currentSession = new UserAuthSession
        {
          AppKey = appInfo.AppKey,
          CreateTime = DateTime.Now,
          InvalidTime = DateTime.Now.AddYears(1),
          IpAddress = Request.UserHostAddress,
          SessionKey = Guid.NewGuid().ToString().ToMd5(),
          UserName = userInfo.UserName
        };

        //创建Session
        _authSessionService.Create(currentSession);
      }
      else
      {
        //延长有效期,默认一年
        _authSessionService.ExtendValid(currentSession.SessionKey);
      }

      //记录用户授权日志
      _userAuthOperateService.Create(new UserAuthOperate
      {
        CreateTime = DateTime.Now,
        IpAddress = Request.UserHostAddress,
        Remark = string.Format("{0} 登录 {1} 授权成功", currentSession.UserName, appInfo.Title),
        SessionKey = currentSession.SessionKey
      }); 104 
      var redirectUrl = string.Format("{0}?SessionKey={1}&SessionUserName={2}",
        appInfo.ReturnUrl, 
        currentSession.SessionKey, 
        userInfo.UserName);

      //跳转默认回调页面
      return Redirect(redirectUrl);
    }
  }
Memcached会话标识验证核心代码:
public class PassportController : ApiController
  {
    private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService();
    private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService();

    public bool Get(string sessionKey = "", string remark = "")
    {
      if (_authSessionService.GetCache(sessionKey))
      {
        _userAuthOperateService.Create(new UserAuthOperate
        {
          CreateTime = DateTime.Now,
          IpAddress = Request.RequestUri.Host,
          Remark = string.Format("验证成功-{0}", remark),
          SessionKey = sessionKey
        });

        return true;
      }

      _userAuthOperateService.Create(new UserAuthOperate
      {
        CreateTime = DateTime.Now,
        IpAddress = Request.RequestUri.Host,
        Remark = string.Format("验证失败-{0}", remark),
        SessionKey = sessionKey
      });

      return false;
    }
  }
ログイン後にコピー

クライアント認証検証フィルター属性



public class SSOAuthAttribute : ActionFilterAttribute
  {
    public const string SessionKey = "SessionKey";
    public const string SessionUserName = "SessionUserName";

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      var cookieSessionkey = "";
      var cookieSessionUserName = "";

      //SessionKey by QueryString
      if (filterContext.HttpContext.Request.QueryString[SessionKey] != null)
      {
        cookieSessionkey = filterContext.HttpContext.Request.QueryString[SessionKey];
        filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionKey, cookieSessionkey));
      }

      //SessionUserName by QueryString
      if (filterContext.HttpContext.Request.QueryString[SessionUserName] != null)
      {
        cookieSessionUserName = filterContext.HttpContext.Request.QueryString[SessionUserName];
        filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionUserName, cookieSessionUserName));
      }

      //从Cookie读取SessionKey
      if (filterContext.HttpContext.Request.Cookies[SessionKey] != null)
      {
        cookieSessionkey = filterContext.HttpContext.Request.Cookies[SessionKey].Value;
      }

      //从Cookie读取SessionUserName
      if (filterContext.HttpContext.Request.Cookies[SessionUserName] != null)
      {
        cookieSessionUserName = filterContext.HttpContext.Request.Cookies[SessionUserName].Value;
      }

      if (string.IsNullOrEmpty(cookieSessionkey) || string.IsNullOrEmpty(cookieSessionUserName))
      {
        //直接登录
        filterContext.Result = SsoLoginResult(cookieSessionUserName);
      }
      else
      {
        //验证
        if (CheckLogin(cookieSessionkey, filterContext.HttpContext.Request.RawUrl) == false)
        {
          //会话丢失,跳转到登录页面
          filterContext.Result = SsoLoginResult(cookieSessionUserName);
        }
      }

      base.OnActionExecuting(filterContext);
    }

    public static bool CheckLogin(string sessionKey, string remark = "")
    {
      var httpClient = new HttpClient
      {
        BaseAddress = new Uri(ConfigurationManager.AppSettings["SSOPassport"])
      };

      var requestUri = string.Format("api/Passport?sessionKey={0}&remark={1}", sessionKey, remark);

      try
      {
        var resp = httpClient.GetAsync(requestUri).Result;

        resp.EnsureSuccessStatusCode();

        return resp.Content.ReadAsAsync<bool>().Result;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    private static ActionResult SsoLoginResult(string username)
    {
      return new RedirectResult(string.Format("{0}/passport?appkey={1}&username={2}",
          ConfigurationManager.AppSettings["SSOPassport"],
          ConfigurationManager.AppSettings["SSOAppKey"],
          username));
    }
  }
ログイン後にコピー

SSO 認証属性の使用例:



[SSOAuth]
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      return View();
    }

    public ActionResult About()
    {
      ViewBag.Message = "Your application description page.";

      return View();
    }

    public ActionResult Contact()
    {
      ViewBag.Message = "Your contact page.";

      return View();
    }
  }
ログイン後にコピー

概要:

ドラフトのサンプルコード コードのパフォーマンスは、ここで確認できます。最適化の余地はまだ多くあり、SSO アプリケーション認証ログイン ページには、ユーザー アカウントが存在しない、パスワードが間違っているなどの一連のプロンプト メッセージも表示されます。ビジネス コードが基本的に正しく実行されている後の段階では、AppSecret 秘密キー署名検証、IP 範囲検証、固定セッション リクエスト攻撃、SSO 認証ログイン インターフェイスでの
検証コード

の有効化など、より多くのセキュリティ レベルの最適化を検討できます。自動セッション キャッシュの再構築、SSo サーバー、キャッシュの水平スケーリングなど。

以上がASP.NET MVC SSOシングルサインオン設計例の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

壁紙エンジンで別のアカウントにログインした後、他の人の壁紙をダウンロードした場合はどうすればよいですか? 壁紙エンジンで別のアカウントにログインした後、他の人の壁紙をダウンロードした場合はどうすればよいですか? Mar 19, 2024 pm 02:00 PM

自分のコンピュータで他人の Steam アカウントにログインし、その他人のアカウントに壁紙ソフトウェアがインストールされている場合、自分のアカウントに切り替えた後、Steam は他人のアカウントに登録されている壁紙を自動的にダウンロードします。 Steam クラウドの同期をオフにします。別のアカウントにログインした後に、wallpaperengine が他の人の壁紙をダウンロードした場合の対処方法 1. 自分の steam アカウントにログインし、設定でクラウド同期を見つけて、steam クラウド同期をオフにします。 2. 以前にログインしたことのある他の人の Steam アカウントにログインし、壁紙クリエイティブ ワークショップを開き、サブスクリプション コンテンツを見つけて、すべてのサブスクリプションをキャンセルします。 (将来壁紙が見つからない場合は、まず壁紙を収集してからサブスクリプションをキャンセルできます) 3. 自分の Steam に戻ります。

小紅書で以前のアカウントにログインするにはどうすればよいですか?再接続後に元の番号が失われた場合はどうすればよいですか? 小紅書で以前のアカウントにログインするにはどうすればよいですか?再接続後に元の番号が失われた場合はどうすればよいですか? Mar 21, 2024 pm 09:41 PM

ソーシャル メディアの急速な発展に伴い、Xiaohongshu は多くの若者が生活を共有し、新製品を探索するための人気のプラットフォームになりました。使用中に、ユーザーが以前のアカウントにログインできない場合があります。この記事では、Xiaohongshuで古いアカウントにログインできない問題の解決方法と、バインドを変更した後に元のアカウントが失われる可能性への対処方法について詳しく説明します。 1. 小紅書の前のアカウントにログインするにはどうすればよいですか? 1. パスワードを取得してログインします。Xiaohongshu に長期間ログインしない場合、アカウントがシステムによってリサイクルされる可能性があります。アクセス権を復元するには、パスワードを取得してアカウントへのログインを再試行します。操作手順は以下の通りです。 (1) 小紅書アプリまたは公式サイトを開き、「ログイン」ボタンをクリックします。 (2) 「パスワードを取得」を選択します。 (3) アカウント登録時に使用した携帯電話番号を入力してください

ZTE 5G ポータブル Wi-Fi U50S が初期価格 NT$899 で発売:最大ネットワーク速度 500Mbps ZTE 5G ポータブル Wi-Fi U50S が初期価格 NT$899 で発売:最大ネットワーク速度 500Mbps Apr 26, 2024 pm 03:46 PM

4月26日のニュースによると、ZTEの5GポータブルWi-Fi U50Sが正式に販売され、価格は899元からとなっている。外観デザインに関しては、ZTE U50S ポータブル Wi-Fi はシンプルでスタイリッシュで、持ちやすく、梱包しやすいです。サイズは159/73/18mmで持ち運びが簡単で、いつでもどこでも5G高速ネットワークを楽しむことができ、妨げられないモバイルオフィスとエンターテインメント体験を実現します。 ZTE 5G ポータブル Wi-Fi U50S は、最大 1800Mbps のピーク レートの高度な Wi-Fi 6 プロトコルをサポートし、Snapdragon X55 高性能 5G プラットフォームを利用して、ユーザーに非常に高速なネットワーク エクスペリエンスを提供します。 5G デュアルモード SA+NSA ネットワーク環境と Sub-6GHz 周波数帯域をサポートするだけでなく、測定されたネットワーク速度は驚異的な 500Mbps に達することもあり、これは簡単に満足できます。

レトロトレンド! HMDとハイネケンが共同で折りたたみ式携帯電話を発売:透明なシェルデザイン レトロトレンド! HMDとハイネケンが共同で折りたたみ式携帯電話を発売:透明なシェルデザイン Apr 17, 2024 pm 06:50 PM

4月17日のニュースによると、HMDは有名なビールブランドのハイネケンとクリエイティブ企業のボデガと提携して、ユニークな折りたたみ式携帯電話「The Boring Phone」を発売した。この携帯電話は、デザインの革新性だけでなく、機能面でも自然に立ち返り、人々を本当の人間関係に戻し、友人と飲む純粋な時間を楽しむことを目指しています。退屈な携帯電話は、ユニークな透明なフリップデザインを採用し、シンプルでありながらエレガントな美しさを示しています。内部には 2.8 インチ QVGA ディスプレイ、外部には 1.77 インチ ディスプレイが装備されており、ユーザーに基本的な視覚的インタラクション エクスペリエンスを提供します。写真に関しては、3,000万画素のカメラしか搭載されていませんが、日常の簡単な作業には十分です。

Baidu Netdisk Web バージョンに入るにはどうすればよいですか? Baidu Netdisk Web 版ログイン入口 Baidu Netdisk Web バージョンに入るにはどうすればよいですか? Baidu Netdisk Web 版ログイン入口 Mar 13, 2024 pm 04:58 PM

Baidu Netdisk は、さまざまなソフトウェア リソースを保存できるだけでなく、他のユーザーと共有することもできます。複数端末の同期をサポートしています。コンピュータにクライアントがダウンロードされていない場合は、Web バージョンに入ることができます。では、Baidu Netdisk Web バージョンにログインするにはどうすればよいでしょうか?詳しい紹介を見てみましょう。 Baidu Netdisk Web バージョンのログイン入り口: https://pan.baidu.com (リンクをコピーしてブラウザで開きます) ソフトウェアの紹介 1. 共有 ファイル共有機能を提供し、ユーザーはファイルを整理し、必要な友人と共有できます。 2. クラウド: メモリをあまり消費せず、ほとんどのファイルはクラウドに保存されるため、コンピュータのスペースを効果的に節約できます。 3. フォト アルバム: クラウド フォト アルバム機能をサポートし、写真をクラウド ディスクにインポートし、全員が閲覧できるように整理します。​

小紅書がアカウントしか覚えていない場合、ログインするにはどうすればよいですか?アカウントを取得する方法を覚えていますか? 小紅書がアカウントしか覚えていない場合、ログインするにはどうすればよいですか?アカウントを取得する方法を覚えていますか? Mar 23, 2024 pm 05:31 PM

小紅書は現在、多くの人々の日常生活に溶け込んでおり、その豊富なコンテンツと便利な操作方法でユーザーは楽しんでいます。アカウントのパスワードを忘れてしまうこともありますが、アカウントだけは覚えているのにログインできないのはとても困ります。 1. Xiaohonshu がアカウントしか覚えていない場合、ログインするにはどうすればよいですか?パスワードを忘れた場合は、携帯電話の確認コードを使用して小紅書にログインできます。具体的な操作は次のとおりです: 1. 小紅書アプリまたはウェブ版の小紅書を開きます; 2. 「ログイン」ボタンをクリックし、「アカウントとパスワードでログイン」を選択します; 3. 「パスワードをお忘れですか?」ボタンをクリックします; 4.アカウント番号を入力して「次へ」をクリックします; 5. システムから携帯電話に確認コードが送信されますので、確認コードを入力して「OK」をクリックします; 6. 新しいパスワードを設定して確認します。サードパーティのアカウント (次のような) を使用することもできます。

Honor Magic V3 が AI デフォーカス眼保護技術をデビュー: 近視の進行を効果的に軽減 Honor Magic V3 が AI デフォーカス眼保護技術をデビュー: 近視の進行を効果的に軽減 Jul 18, 2024 am 09:27 AM

7月12日のニュースによると、Honor Magic V3シリーズは本日正式にリリースされ、新しいHonor Vision Soothing Oasisアイプロテクションスクリーンを搭載しており、スクリーン自体は高スペックで高品質であると同時に、AIアクティブアイプロテクションの導入も先駆けとなっています。テクノロジー。近視を軽減する伝統的な方法は「近視メガネ」であると報告されています。近視メガネの度数は均等に分散され、視野の中心領域は網膜上に結像されますが、周辺領域は網膜の後ろに結像されます。網膜は像が遅れていると認識し、眼軸方向の成長を促進し、その度数が深くなります。現在、近視の進行を軽減する主な方法の 1 つは、「デフォーカス レンズ」です。中央領域は通常の度数で、周辺領域は光学設計の隔壁によって調整され、周辺領域の像が収まります。網膜の前。

Google Chrome でアカウントにログインできない場合はどうすればよいですか? Google Chromeアカウントにログインできない原因の解決策 Google Chrome でアカウントにログインできない場合はどうすればよいですか? Google Chromeアカウントにログインできない原因の解決策 Mar 13, 2024 pm 02:10 PM

Google Chrome でアカウントにログインできない場合はどうすればよいですか?多くのユーザーがこのソフトウェアを使用する場合、一部の機能はユーザーが Google アカウントにログインして使用する必要がありますが、何度試してもログインできず、多くのユーザーはこの問題に直面し、その方法がわかりません。今日のソフトウェア チュートリアルの内容が皆様のお役に立てれば幸いです。解決策は次のとおりです。 1. デスクトップ上のブラウザをクリックし、開くと、次のようなものが表示されます。 2. この時点でログイン画面が表示された場合はクリックし、表示されない場合は右上隅をクリックします。 3. 「ログイン」をクリックし、アカウント番号を入力します(@以降のアカウントは入力する必要はありません)。「次へ」をクリックします。 4. パスワードを入力し、このプロンプトが表示されたら、「有効にする」をクリックします。

See all articles