OpenIDを使用した認証サーバーの設定


This article is part of a series called Setting up an Authorization Server with OpenIddict. The articles in this series will guide you through the process of setting up an OAuth2 + OpenID Connect authorization server on the the ASPNET Core platform using OpenIddict.


  • パート2 : Create ASPNETプロジェクト




  • ロビンソン / 認証サーバ


    OpenIDDictで実装された認証サーバ。


    この部分では、我々の認可サーバーのための最小限のセットアップとして機能するASPNETコアプロジェクトを作成します.MVCを使用してページを提供し、基本的なログインフォームを含むプロジェクトに認証を追加します.

    新しい空のASPNETプロジェクトを作成します。


    前の記事で述べたように、認証サーバーは別のWebアプリケーションです.次のコンテンツは、ユーザー名のパスワードログインでASPNETコアアプリケーションを設定することをご案内します.使用しないほうを選ぶASPNET Core Identity 物事を本当に簡単に保つ.基本的にすべてのユーザー名のパスワードの組み合わせが動作します.
    新しいWebアプリケーションの作成から始めましょうAuthorizationServer 使用ASP.NET Core Empty template :
    dotnet new web --name AuthorizationServer
    
    我々は、このプロジェクトで動作します、我々はこのガイドでソリューションファイルを追加しません.
    OpenIDDictは私たちはhttps ローカルで開発しても、プロトコル.ローカル証明書が信頼されるようにするには、次のコマンドを実行しなければなりません.
    dotnet dev-certs https --trust
    
    Windowsでは、証明書ストアとOSX上の証明書がキーチェーンに追加されます.Linuxでは、distrosを通して証明書を信頼する標準的な方法はありません.この主題についてもっと読んでくださいHanselman's blog article .
    すべての期待通りに動作するアプリケーションを起動します
    dotnet run --project AuthorizationServer
    
    訪問https://localhost:5001 . あなたはHello World! あなたのブラウザで.

    MVC


    ASPNETコア空のテンプレートに基づいたプロジェクトを作成しました.これは非常に最小限のテンプレートです.私は意図的にこれをしました、私が物事をはっきりさせて、単純にしておくためにできるだけ私のプロジェクトで少しの『雑音』を持つのが好きであるので.
    このテンプレートの使用の欠点はMVC 我々自身.まず、MVCを変更することによってStartup.cs クラス
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    namespace AuthorizationServer
    {
        public class Startup
        {
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllersWithViews();
            }
    
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapDefaultControllerRoute();
                });
            }
        }
    }
    
    MVCは、呼び出しによって構成されますservices.AddControllersWithViews() . エンドポイントはデフォルトルーティングを使用する設定です.また、静的ファイルの提供を有効にして、WWWRootフォルダーからスタイルシートを提供する必要があります.
    さて、コントローラ、ビュー、ビューモデルを作成しましょう.プロジェクトフォルダ内の次のフォルダ構造を追加します.
    /Controllers
    /Views
    /Views/Home  
    /Views/Shared
    /ViewModels
    /wwwroot
    /wwwroot/css
    

    レイアウト


    最初の項目は、レイアウトファイル_Layout.cshtmlViews/Shared フォルダ.このファイルは、アプリケーションの一般的なレイアウト、および負荷を定義しますBootstrap とjnからのjQuery.jQueryはブートストラップの依存性です.
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"/>
    
        <title>OpenIddict - Authorization Server</title>
    
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" crossorigin="anonymous">
        <link rel="stylesheet" href="~/css/site.css"/>
    </head>
    <body>
    <div class="container-sm mt-3">
        <div class="row mb-3">
            <div class="col text-center">
                <h1>
                    Authorization Server
                </h1>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-12 col-md-8 col-xl-4 offset-md-2 offset-xl-4 text-center mb-3">
                @RenderBody()
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
    </body>
    </html>
    
    レイアウトとビューの作業には、\Views フォルダ_ViewStart.cshtml
    @{
      Layout = "_Layout";
    }
    
    _ViewImports.cshtml
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    

    のホームページ


    基本を加えるHomeController/Controllers フォルダには、ホームページを提供する唯一の目的があります.
    using Microsoft.AspNetCore.Mvc;
    
    namespace AuthorizationServer.Controllers
    {
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
        }
    }
    
    追加Index.cshtmlViews/Home HomeControllerが提供するフォルダ
    <h2>MVC is working</h2>
    

    スタイルシート


    最後に、少なくとも、我々はいくつかのスタイリングが必要です.スタイルシートを追加するsite.csswwwroot\css フォルダ
    :focus {
      outline: 0 !important;
    }
    .input-validation-error {
      border: 1px solid darkred;
    }
    form {
      width: 100%;
    }
    .form-control {
      border:0;
      border-radius: 0;
      border-bottom: 1px solid lightgray;
      font-size:0.9rem;
    }
    .form-control:focus{
      border-bottom-color: lightgray;
      box-shadow: none;
    }
    .form-control.form-control-last {
      border-bottom: 0;
    }
    .form-control::placeholder {
      opacity: 0.6;
    }
    .form-control.input-validation-error {
      border: 1px solid darkred;
    } 
    
    いくつかのスタイル規則は、後に作成するログインフォームを予想するスタイルシートに既に追加されています.
    SASSを使ったり、SASSとブートストラップをカスタマイズしたい場合は、ASSNETでブートストラップのSASSを設定してください.
    アプリケーションを実行し、すべてが動作しているかどうかを確認してください.

    認証を有効にする


    ASP .ネットコアauthenticationIAuthenticationService . 認証サービスは認証ハンドラを使用して認証関連のアクションを完了します.
    認証ハンドラは起動時に登録され、設定オプションは「scheme」と呼ばれます.認証方式は認証サービスを登録することによって指定されるStartup.ConfigureServices .
    このプロジェクトについてはcookie authentication , そこで、クッキー認証スキームをConfigureServices メソッドStartup.cs :
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.LoginPath = "/account/login";
            });
    }
    
    ログインパスは/account/login , 我々はすぐにこのエンドポイントを実装します.
    認証された認証方式を使用する認証ミドルウェアはUseAuthentication アプリケーションの拡張方法IApplicationBuilder :
    app.UseRouting();
    
    app.UseAuthentication();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
    
    への呼び出しUseAuthentication への呼び出しの後に作られますUseRouting , 経路情報が認証決定のために利用可能であるようにUseEndpoints , ユーザがエンドポイントにアクセスする前に認証されるようにします.

    ログインページ


    認証が有効になったので、ユーザを認証するログインページが必要になります.
    まず、ユーザーを認証するために必要な情報を含むログインビューモデルを作成します.必ずこのファイルをViewModels フォルダ
    using System.ComponentModel.DataAnnotations;
    
    namespace AuthorizationServer.ViewModels
    {
        public class LoginViewModel
        {
            [Required]
            public string Username { get; set; }
            [Required]
            public string Password { get; set; }
            public string ReturnUrl { get; set; }
        }
    }
    
    フォルダを作成するAccountViews フォルダとログインビューを追加します.Login.cshtml , ログインフォームを含む
    @model AuthorizationServer.ViewModels.LoginViewModel
    <form autocomplete="off" asp-route="Login">
        <input type="hidden" asp-for="ReturnUrl"/>
        <div class="card">
            <input type="text" class="form-control form-control-lg" placeholder="Username" asp-for="Username" autofocus>
            <input type="password" class="form-control form-control-lg form-control-last" placeholder="Password" asp-for="Password">
        </div>
        <p>
            <button type="submit" class="btn btn-dark btn-block mt-3">Login</button>
        </p>
    </form>
    
    最後にAccountController :
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using AuthorizationServer.ViewModels;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    
    namespace AuthorizationServer.Controllers
    {
        public class AccountController : Controller
        {
            [HttpGet]
            [AllowAnonymous]
            public IActionResult Login(string returnUrl = null)
            {
                ViewData["ReturnUrl"] = returnUrl;
                return View();
            }
    
            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Login(LoginViewModel model)
            {
                ViewData["ReturnUrl"] = model.ReturnUrl;
    
                if (ModelState.IsValid) 
                {
                    var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Name, model.Username)
                    };
    
                    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    
                    await HttpContext.SignInAsync(new ClaimsPrincipal(claimsIdentity));
    
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return Redirect(model.ReturnUrl);
                    }
    
                    return RedirectToAction(nameof(HomeController.Index), "Home");
                }
    
                return View(model);
            }
    
            public async Task<IActionResult> Logout()
            {
                await HttpContext.SignOutAsync();
    
                return RedirectToAction(nameof(HomeController.Index), "Home");
            }
        }
    }
    
    だから、ここで何が起こる?
    アカウントコントローラに2つのログインアクション(GETとPOST)があります.
    get actionは、作成したログインフォームを提供します.オプションのクエリパラメータがあります.returlUrl どの店にViewData , それで、我々は成功したログインの後、ユーザーをリダイレクトするためにこれを使うことができます.
    ポストアクションはもっと面白い.ファーストModelState が有効です.つまり、ユーザ名とパスワードが必要です.ここでは資格情報をチェックしません.この例ではどんな組み合わせも有効です.通常、これはあなたのデータベースに対する資格情報をチェックする場所です.
    モデル状態が有効な場合、クレームIDが構築されます.ユーザーの名前を1つ追加します.注意してください、我々はクッキー認証方式を指定しますCookieAuthenticationDefaults.AuthenticationScheme ) クレームアイデンティティを作成するとき.これは基本的に文字列で、Startup.cs クッキー認証を設定するときのクラス.
    The SignInAsync メソッドは、CookieAuthenticationHandlerを呼び出すAuthenticationServiceを呼び出す拡張メソッドです.これは、クレームIDの作成時に指定したスキームです.
    サインをした後に、ユーザをリダイレクトする必要があります.戻りURLが指定された場合、ローカルURLであるかどうかを確認しますprevent open redirect attacks リダイレクトする前に.さもなければ、ユーザはホームページにリダイレクトされます.
    最後のアクションログアウトは、認証サービスをユーザに署名するよう要求します.認証サービスは、認証ミドルウェア、我々のケースでは、クッキー認証ミドルウェアを呼び出すと、ユーザーを署名する.

    ホームページ更新


    ホームページを更新Views/Home/Index.cshtml ):
    @using Microsoft.AspNetCore.Authentication
    
    @if (User.Identity.IsAuthenticated)
    {
        var authenticationResult = await Context.AuthenticateAsync();
        var issued = authenticationResult.Properties.Items[".issued"];
        var expires = authenticationResult.Properties.Items[".expires"];
        <div>
            <p>You are signed in as</p>
            <h2>@User.Identity.Name</h2>
            <hr/>
            <dl>
                <dt>Issued</dt>
                <dd>@issued</dd>
                <dt>Expires</dt>
                <dd>@expires</dd>
            </dl>
            <hr/>
            <p><a class="btn btn-dark" asp-controller="Account" asp-action="Logout">Sign out</a></p>
        </div>
    }
    
    @if (!User.Identity.IsAuthenticated)
    {
        <div>
            <p>You are not signed in</p>
            <p><a class="btn btn-sm btn-dark" asp-controller="Account" asp-action="Login">Sign in</a></p>
        </div>
    }
    
    ユーザーが認証されるならば、我々はユーザー名、現在のセッションに関する情報とサインアウトボタンを示します.ユーザーが認証されていない場合は、ログインフォームにユーザーをナビゲートする記号インボタンを表示します.
    アプリケーションを起動するには、ホームページの「ボタン」ボタンを参照してください.

    クリックするときSign in ログインフォームに移動します.

    サインをするには、ちょうどランダムな資格情報、すべての空の値を記入する罰金です.
    すべてが正しく動作するならば、あなたはあなたがサインされることを示すホームページにリダイレクトされなければなりません:


    現在、我々は基本的なASPNETコアプロジェクトを認証を実行して実行している、これまでのところファンシーはありません.OpenIDDictをプロジェクトに追加し、クライアントの資格情報の流れを実装します.