OpenID Connectによるユーザ認証の追加

このクイックスタートでは、私たちのIdentityServerにOpenID Connectプロトコルによる対話型ユーザー認証のサポートを追加したいと考えています。

これが完了すると、IdentityServerを認証に使用するMVCアプリケーションを作成します。

UIの追加

OpenID Connectに必要なすべてのプロトコルサポートは、すでにIdentityServerに組み込まれています。ログイン、ログアウト、同意とエラーに必要なUI部品を提供する必要があります。

ルック・アンド・フィールと正確なワークフローは、すべてのIdentityServer実装で常に異なると思われますが、私たちはMVCベースのサンプルUIを提供しています。

このUIは、 クイックスタートUIレポ にあります。このレポを複製またはダウンロードし、コントローラ、ビュー、モデル、およびCSSをIdentityServer Webアプリケーションにドロップすることができます。

または、IdentityServer Webアプリケーションと同じディレクトリにあるコマンドラインからこのコマンドを実行して、ダウンロードを自動化することもできます。:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

Unix / Linuxの場合:

\curl -L https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.sh | bash

MVC UIアセ​​ットを追加したら、DIシステムとパイプラインの両方でMVCをホスティングアプリケーションに追加する必要があります。MVCを追加 ConfigureServices して AddMvc 拡張メソッド:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

パイプラインの最後のミドルウェアとしてMVCを追加 Configure して UseMvc 拡張メソッド:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseIdentityServer();

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

詳細については、クイックスタートUIの readme を参照してください。

注釈

release UIリポジトリのブランチには、最新の安定版と一致するUIがあります。 dev branch はIdentityServer4の現在の dev のビルドと一緒に行きます。特定のバージョンのUIをお探しの場合は、タグを確認してください。

しばらく時間をかけてコントローラーとモデルを調べ、理解していれば簡単に将来の変更を加えることができます。ほとんどのコードは、「機能フォルダ」スタイルを使用して「クイックスタート」フォルダに保存されています。このスタイルがあなたに合っていない場合は、自由にコードを整理してください。

MVCクライアントの作成

次に、ソリューションにMVCアプリケーションを追加します。そのためには、ASP.NET Core "Web Application"(つまりMVC)テンプレートを使用します。ウィザードの「認証」設定を構成しないでください。このクイックスタートで手動で行います。プロジェクトを作成したら、ポート5002を使用するようにアプリケーションを設定します(その方法については、概要の部分を参照してください)。

OpenID Connect認証のサポートをMVCアプリケーションに追加するには、以下をConfigureServicesinに追加しますStartup。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";

            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;

            options.ClientId = "mvc";
            options.SaveTokens = true;
        });
}

AddAuthenticationDIに認証サービスを追加します。プライマリが(を介してユーザを認証するための手段として、私たちはクッキーを使用している"Cookies"などDefaultScheme)。私たちは、ユーザーにログインする必要があるときに、OpenID Connectスキームを使用DefaultChallengeSchemeする"oidc"ため、を設定します。

次に、AddCookieCookieを処理できるハンドラを追加します。

最後に、AddOpenIdConnectOpenID Connectプロトコルを実行するハンドラを設定するために使用されます。これAuthorityは、IdentityServerを信頼していることを示しています。私たちは、その後、経由でこのクライアントを識別するClientId。 SignInSchemeOpenID Connectプロトコルが完了したら、Cookieハンドラを使用してCookieを発行するために使用されます。またSaveTokens、Cookie内のIdentityServerからトークンを永続化するために使用されます(後で必要になるため)。

また、JWTクレームタイプマッピングを無効にして、よく知られているクレーム(例えば、 'sub'や 'idp'など)が無修正で流れるようにしました。

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

そして、認証サービスを追加し、それぞれの要求に応じて実行することを確認するためUseAuthenticationにConfigureでStartup:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseAuthentication();

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

認証ミドルウェアは、MVCの前にパイプラインで追加する必要があります。

最後のステップは、認証ハンドシェイクをトリガーすることです。そのためには、ホームコントローラーに移動し[Authorize]、アクションの1つを追加します。そのアクションのビューを変更して、ユーザーの主張を表示します(例:

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

ブラウザを使用してそのコントローラに移動すると、IdentityServerへのリダイレクトが試みられます。これは、MVCクライアントがまだ登録されていないためエラーになります。

OpenID Connect IDスコープのサポートの追加

OAuth 2.0と同様に、OpenID Connectもスコープの概念を使用しています。ここでも、スコープは保護したい、そしてクライアントがアクセスしたいものを表しています。OAuthとは対照的に、OIDCのスコープはAPIを表すのではなく、ユーザーID、名前、電子メールアドレスなどのIDデータを表します。

新しいヘルパー(in )を追加して、オブジェクトのコレクションを作成することにより、標準openid(subject id)とprofile(first name、last nameなど..)スコープのサポートを追加します。Config.csIdentityResource

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}

注釈

すべての標準的なスコープとそれに対応するクレームは、OpenID Connect 仕様

これらのアイデンティティーリソースをIdentityServerの設定に追加する必要がありますStartup.cs。AddInMemoryIdentityResources電話をかける場合は、拡張方法を使用してくださいAddIdentityServer():

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

OpenID Connect暗黙のフローのためのクライアントの追加

最後の手順は、MVCクライアントの新しい設定エントリをIdentityServerに追加することです。

OpenID Connectベースのクライアントは、これまでに追加したOAuth 2.0クライアントと非常によく似ています。しかし、OIDCのフローは常にインタラクティブなので、リダイレクトURLを設定に追加する必要があります。

クライアント構成に次のものを追加します。

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        // other clients omitted...

        // OpenID Connect implicit flow client (MVC)
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,

            // where to redirect to after login
            RedirectUris = { "http://localhost:5002/signin-oidc" },

            // where to redirect to after logout
            PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };
}

クライアントのテスト

最終的には、新しいMVCクライアントのためのすべての場所にする必要があります。

保護されたコントローラの操作に移動して、認証ハンドシェイクをトリガーします。IdentityServerのログインページへのリダイレクトが表示されます。

../_images/3_login.png

ログインに成功すると、同意画面が表示されます。ここで、ユーザは、自分のアイデンティティ情報をクライアントアプリケーションにリリースしたいかどうかを決定することができる。

注釈

RequireConsentクライアントオブジェクトのプロパティを使用して、クライアントごとに同意を無効にすることができます。

../_images/3_consent.png

最後に、ブラウザはクライアントアプリケーションにリダイレクトされ、クライアントアプリケーションはユーザーの主張を示します。

../_images/3_claims.png

注釈

開発中に、トークンを検証できないことを示す例外が表示されることがあります。これは、署名キーマテリアルがオンザフライで作成され、メモリ内でのみ保持されるためです。この例外は、クライアントとIdentityServerが同期しなくなった場合に発生します。次回メタデータが追いついたときにクライアントで操作を繰り返すだけで、すべて正常に動作します。

サインアウトの追加

最後のステップは、MVCクライアントにサインアウトを追加することです。

IdentityServerのような認証サービスでは、ローカルアプリケーションのCookieをクリアするだけでは不十分です。さらに、中央シングルサインオンセッションをクリアするために、IdentityServerへの往復を行う必要があります。

正確なプロトコル手順は、OpenID Connectミドルウェア内で実装されています。単に、次のコードを一部のコントローラに追加してログアウトをトリガーします。

public async Task Logout()
{
    await HttpContext.SignOutAsync("Cookies");
    await HttpContext.SignOutAsync("oidc");
}

これにより、ローカルCookieがクリアされ、IdentityServerにリダイレクトされます。IdentityServerはクッキーをクリアして、ユーザにMVCアプリケーションに戻るためのリンクを与えます。

さらなる実験

前述のように、OpenID Connectミドルウェアはデフォルトでプロファイルスコープを要求します。このスコープには、名前やウェブサイトなどの主張も含まれます。

これらのクレームをユーザに追加して、IdentityServerがそれらをアイデンティティトークンに入れることができます:

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password",

            Claims = new []
            {
                new Claim("name", "Alice"),
                new Claim("website", "https://alice.com")
            }
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password",

            Claims = new []
            {
                new Claim("name", "Bob"),
                new Claim("website", "https://bob.com")
            }
        }
    };
}

次に認証すると、クレームページに追加のクレームが表示されます。

クレームを追加して、さらに多くの範囲を自由に感じてください。ScopeOpenID Connectミドルウェアのプロパティは、認証時にIdentityServerに送信されるスコープを設定する場所です。

また、トークンに対する要求の取得は拡張性の点であることも注目に値するIProfileService。私たちが使用しているのでAddTestUsers、TestUserProfileServiceデフォルトで使用されます。ここでソースコード を調べることで、その動作を確認することができます。