「[[Open棟梁 wiki>https://opentouryo.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>汎用認証サイトのファーストステップガイド]]
--[[汎用認証サイトのファーストステップガイド (1)]]
--[[汎用認証サイトのファーストステップガイド (2)]]
--[[汎用認証サイトのファーストステップガイド (3)]]
--汎用認証サイトのファーストステップガイド (4)
--[[汎用認証サイトのファーストステップガイド (5)]]

*目次 [#hddf7023]
#contents

*概要 [#lbdaf1e3]
[[汎用認証サイト(Multi-purpose Authentication Site)]]~
の導入前の評価を行うためのファーストステップガイド。

(4) では、「認証連携コードの実装」を行う。

*汎用認証サイトをセットアップする。 [#m6718c37]
-適当なところに汎用認証サイトをセットアップする。
-[[3 分割テスト>汎用認証サイトのファーストステップガイド (3)#r68f6218]]で行ったように、ポート番号が違うならlocalhostでも良い。
-ここでは、別サーバーのIIS上にデプロイ、セットアップしたので汎用認証サイトは常に実行可能状態にある。
-ローカル開発環境でテストする場合は、必要に応じて、汎用認証サイトをデバッグ起動して実行可能状態にする。

*クライアントのプロジェクトを作成する。 [#l8d51863]
ここでは、クライアントのプロジェクトとして、ASP.NET MVCを選択する。

**ASP.NET MVCのプロジェクトを新規作成する。 [#v7dfdc59]
ASP.NET MVCの(ASP.NET Web Application)プロジェクトを新規作成する。

[メニュー] ---> [新規作成] --->
>[プロジェクト] ---> [ASP.NET Web Application(.NET Framework)]

***新しいプロジェクト [#le7af872]
-任意のパスを指定

-名前を入力
--例えば[WebApplication1]という既定の名称を使用する。
--ソリューション名も同じ名称のままにする。

-[OK]ボタンを押下。

***テンプレート選択 [#s719107d]
テンプレート選択画面で以下のように選択する。

-テンプレートとして、[MVC]を選択する。
-[認証の変更ボタン]を押下し、[認証なし]に変更する。
-[OK]ボタンを押下してプロジェクトを作成する。
-※ [クラウドにホストする]チェック ボックスのチェックは外す。

**余分なコードを削除する。 [#tbfa323e]
***Controller [#k9aeec88]
HomeControllerから以下のアクション・メソッドを削除
-About
-Contact

***View [#rc37b85d]

-[[上記のアクション・メソッド>#k9aeec88]]に対応するViewも削除する。
--~/Home/About.cshtml
--~/Home/Contact.cshtml

-_Layout.cshtml

--以下のdivは不要なので消す。
 <div class="navbar navbar-inverse navbar-fixed-top">

--以下を以下で置き換える。
---以下のdivを
 <div class="container body-content">
---以下のステートメントで置き換える。
 @RenderBody()

--以下のような状態になる。
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>@ViewBag.Title - マイ ASP.NET アプリケーション</title>
     @Styles.Render("~/Content/css")
     @Scripts.Render("~/bundles/modernizr")
 </head>
 <body>
     @RenderBody()
 
     @Scripts.Render("~/bundles/jquery")
     @Scripts.Render("~/bundles/bootstrap")
     @RenderSection("scripts", required: false)
 </body>
 </html>

-~/Home/Index.cshtml

--以下を残して全て消す。
 @{
     ViewBag.Title = "Home Page";
 }

*クライアントにRedirectエンドポイントを作成する。 [#we465a2c]
**サンプルコードをコピーする。 [#j5235722]
[[汎用認証サイトのAccountController>https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Controllers/AccountController.cs#L1289]]からサンプルのRedirectエンドポイントである~
AccountController.OAuthAuthorizationCodeGrantClientアクション・メソッドをコピーする。

**サンプルコードを貼り付ける。 [#u2eec88f]
-HomeControllerにコピーしたOAuthAuthorizationCodeGrantClientアクション・メソッドを貼り付ける。

-最初のうちは、ほぼほぼコンパイル エラーになるので、以下のようにコメント アウトし、

-最後に、「return View("");」を加えておく。
 [HttpGet]
 [AllowAnonymous]
 public async Task<ActionResult> OAuthAuthorizationCodeGrantClient(string code, string state)
 {
     // ・・・コメントアウト・・・
     
     return View("");
 }

*汎用認証サイトにRedirectエンドポイントのURLを設定する。 [#dba08db1]
-以下のclient_id部分に、以下のように、Redirectエンドポイントを設定する。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L235
 "f53469c17c5a432f86ce563b7805ab89": {
 "client_secret": "cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM",
 "redirect_uri_code": "http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient",
 "redirect_uri_token": "http://hogehoge0/bbb",
 "client_name": "test_icon"

-なお、このセクションは「CreateClientsIdentity.exe」使用して自動生成できる。

*クライアントにスターターのリンクを設置する。 [#q8d7b767]

**スターターのリンクを取得 [#jd4f0e5f]
-スターターは汎用認証サイトを実行したトップ画面画から取得する。
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=67d328bfe8604aae83fb15fa44780d8b&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L
#ref(0.png,left,nowrap,0)

**スターターのリンクを設置 [#fe72f177]
-スターターの「ホスト:ポート」部分を書き換えてIndex.cshtmlに貼り付ける。
 <a href="http://(クライアント・サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=67d328bfe8604aae83fb15fa44780d8b&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始</a>

-次に、client_idを書き換える。具体的には、「67d328bfe8604aae83fb15fa44780d8b」から「f53469c17c5a432f86ce563b7805ab89」に書き換える。
 <a href="http://(クライアント・サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=f53469c17c5a432f86ce563b7805ab89&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始</a>

*クライアントをデバッグ実行し、仲介コードを確認する。 [#p1b6df91]
**ブレークポイントを仕掛ける。 [#x5c3dcc8]
RedirectエンドポイントであるOAuthAuthorizationCodeGrantClientアクション・メソッドにブレークポイントを仕掛ける。

**クライアントをデバッグ実行してスターターをクリック [#q259f27b]
この状態でクライアント・サイトをデバッグ実行して、スターターをクリックしてみる。

**プレークポイントにブレーク(中断)するのを確認する。 [#rc13061b]

-汎用認証サイトの認証、(認可エンドポイントでの)認可プロセスを経て、

-クライアント・サイトのRedirectエンドポイントである~
OAuthAuthorizationCodeGrantClientアクション・メソッドでブレーク(中断)するのを確認する。

-ここで、以下のように、仲介コードを確認することができる。~
以降コレ(仲介コード)を、AccessTokenとRefreshTokenに変換する処理をじっそうする。
#ref(1.png,left,nowrap,1)

*仲介コードをAccessTokenとRefreshTokenに変換する。 [#b04f025b]
**必要な情報の収集 [#q97ffaa9]
以下を必要とする。

***アクセストークン・リクエストの仕方。 [#k1d931a7]
-アクセストークン・リクエストについては、[[コチラ>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth#yfeb403d]]を参照。

-ザックリと、以下のようなリクエストを送信する。
 POST /token HTTP/1.1
  Host: server.example.com
  Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
  Content-Type: application/x-www-form-urlencoded
 
  grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
  &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

-ここでは、以下のようになる。
 POST /MultiPurposeAuthSite/OAuthBearerToken
 HTTP/1.1
  Host: (汎用認証サイトのアドレス:ポート)
  Authorization: Basic ["client_Id:client_secret"をbase64 url encodeした値]
  Content-Type: application/x-www-form-urlencoded
 
  grant_type=authorization_code&code=[取得した仲介コードの値]

***TokenエンドポイントのURL [#vaa26fc4]
-Tokenエンドポイントのパスは、以下に設定されている。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L201

-汎用認証サイトのURLと繋げて、以下のようになる。
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/OAuthBearerToken

***client_Idとclient_secret [#qc267a07]
-client_Idとclient_secretは以下に設定されている。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L235

-client_Idとclient_secretの値はそれぞれ、~
--client_Id : f53469c17c5a432f86ce563b7805ab89
--client_secret : cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM

>を利用する。

***RedirectエンドポイントのURL [#vaa26fc4]
-[[Redirectエンドポイントは前述の値>#dba08db1]]。

-ここでは、以下のようになる。
 http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient

**[[HttpClient>https://techinfoofmicrosofttech.osscons.jp/index.php?HttpClient%E3%81%AE%E9%A1%9E%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9]]を使用してアクセストークン・リクエストを行う。 [#b8eff20c]

***コード [#l1699430]
だいたい、以下のような感じのコードになる。

 using System;
 using System.Text;
 using System.Collections.Generic;
 using System.Web.Mvc;
 using System.Net.Http;
 using System.Net.Http.Headers;
 using System.Threading.Tasks;
 
 using Microsoft.Owin.Security.DataHandler.Encoder;
 
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
 namespace WebApplication1.Controllers
 {
     public class HomeController : Controller
     {
         public ActionResult Index()
         {
             return View();
         }
 
         [HttpGet]
         [AllowAnonymous]
         public async Task<ActionResult> OAuthAuthorizationCodeGrantClient(string code, string state)
         {
             if (state == "vj9NCxij4L") // CSRF(XSRF)対策のstateの検証は重要
             {
                 HttpClient httpClient = new HttpClient();
 
                 // HttpRequestMessage (Method & RequestUri)
                 HttpRequestMessage httpRequestMessage = new HttpRequestMessage
                 {
                     Method = HttpMethod.Post,
                     RequestUri = new Uri("http://10.231.20.145/MultiPurposeAuthSite/OAuthBearerToken"),
                 };
 
                 // HttpRequestMessage (Headers & Content)
                 httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
                     "Basic",
                     Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(
                         string.Format("{0}:{1}",
                             "f53469c17c5a432f86ce563b7805ab89",
                             "cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM"))));
 
                 httpRequestMessage.Content = new FormUrlEncodedContent(
                     new Dictionary<string, string>
                     {
                         { "grant_type", "authorization_code" },
                         { "code", code },
                         { "redirect_uri", System.Web.HttpUtility.HtmlEncode("http://localhost:62517/Home/OAuthAuthorizationCodeGrantClient") },
                     });
 
                 // HttpResponseMessage
                 HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
                 string response = await httpResponseMessage.Content.ReadAsStringAsync();
 
                 // 汎用認証サイトのOAuth2.0のレスポンスに含まれるaccess_tokenは、id_tokenのようなformatをしている。ここからsubを取得可能。
                 Base64UrlTextEncoder base64UrlEncoder = new Base64UrlTextEncoder();
                 Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
                 JObject jobj = ((JObject)JsonConvert.DeserializeObject(Encoding.UTF8.GetString(base64UrlEncoder.Decode(dic["access_token"].Split('.')[1]))));
 
                 string sub = (string)jobj["sub"];
             }
 
             return View("");
         }
 
     }
 }

***実行結果 [#i62ef920]
-上記の、「dic["access_token"]」の部分が、JWT形式のアクセストークンである。
-このJWT検証には「https://jwt.io/」を使用できる。詳しくは[[コチラ>汎用認証サイトのファーストステップガイド (1)#b6c3cd0c]]を参照。
-subが取得できれば、アクセストークンの取得に成功している。
-必要に応じて、JWTの署名検証、内容検証を行えば、より確実と言える。
-上記の、「dic["access_token"]」の部分が、[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]形式のアクセストークンである。~
汎用認証サイトでは、アクセストークンのformatをASP.NET Identity形式とJWT形式から選択できる。

-必要に応じて、[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]の署名検証、内容検証を行えば、より確実と言える。
--この[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]の署名検証、内容検証には「https://jwt.io/」を使用できる。詳しくは[[コチラ>汎用認証サイトのファーストステップガイド (1)#b6c3cd0c]]を参照。
--"sub"が取得できれば、アクセストークンの取得に成功している。
--最低限、"aud"と"nonce"クレームの内容検証を行うと良い。
--"aud"クレームには、起動パラメタの"client_id"値が格納される。
--"nonce"クレームには、起動パラメタの"state"値が格納される。
--余裕があれば、JWTの署名検証を行うと良いと考える。

#ref(2.png,left,nowrap,2)

***その後 [#u9bd4699]
必要に応じて、/userinfoエンドポイントなどのResourcesServerのWebAPIにアクセスして結果を画面に出力する。

***注意事項 [#z796a2ba]
-基本的に、仲介コードやアクセストークンは画面に露見させないこと。

-このまま画面に表示させるとQuerystringに仲介コードが露見するので、~
必要な情報位を取得した後に、一段、Redirect処理などを経由させると良い。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS