OpenIDDictによる認証サーバの設定-パートIII -クライアント資格情報の流れ
26266 ワード
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.
ロビンソン / 認証サーバ
OpenIDDictで実装された認証サーバ。
openiddictパッケージを追加する
まず、OpenIDDict Nugetパッケージをインストールする必要があります.
dotnet add package OpenIddict
dotnet add package OpenIddict.AspNetCore
dotnet add package OpenIddict.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.InMemory
メインライブラリのほかにもOpenIddict.AspNetCore
パッケージは、このパッケージは、ASPNETコアホストのOpenIDDictの統合を可能にします.OpenIddict.EntityFrameworkCore
パッケージは、Entity Frameworkコアサポートを有効にします.今のところ、我々は、パッケージを使用してメモリ内の実装で動作しますMicrosoft.EntityFrameworkCore.InMemory
.セットアップOpeniddict
OpenIDDictを実行して実行するのに必要最小限のものから始めます.少なくとも1つのOAuth 2.0/OpenID接続フローを有効にする必要があります.を有効にするClient Credentials Flow , これはマシンからマシンへのアプリケーションに適しています.このシリーズの次の部分ではAuthorization Code Flow with PKCE これは、単一ページアプリケーション(SPA)とネイティブ/モバイルアプリケーションの推奨される流れです.
次の変更を開始します
Startup.cs
:public void ConfigureServices(IServiceCollection services)
{
...
services.AddDbContext<DbContext>(options =>
{
// Configure the context to use an in-memory store.
options.UseInMemoryDatabase(nameof(DbContext));
// Register the entity sets needed by OpenIddict.
options.UseOpenIddict();
});
services.AddOpenIddict()
// Register the OpenIddict core components.
.AddCore(options =>
{
// Configure OpenIddict to use the EF Core stores/models.
options.UseEntityFrameworkCore()
.UseDbContext<DbContext>();
})
// Register the OpenIddict server components.
.AddServer(options =>
{
options
.AllowClientCredentialsFlow();
options
.SetTokenEndpointUris("/connect/token");
// Encryption and signing of tokens
options
.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey();
// Register scopes (permissions)
options.RegisterScopes("api");
// Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
options
.UseAspNetCore()
.EnableTokenEndpointPassthrough();
});
}
最初に、DBContextはConfigureServices
メソッド.OpenIDDictは、エンティティフレームワークコア、エンティティフレームワーク6およびMongoDBの箱の中からネイティブにサポートし、また、あなた自身の店を提供することができます.この例では、Entity Frameworkコアを使用し、メモリ内データベースを使用します.The
options.UseOpenIdDict
call openOpenDictが必要とするエンティティセットを登録します.次に、OpenIDDict自身が登録されます.The
AddOpenIddict()
call openOpenDictサービスを登録し、OpenIddictBuilder
OpenIDDictを構成できるクラス.コアコンポーネントは最初に登録されます.OpenIDDictはEntity Frameworkコアを使用するように指示され、前述のDBContextを使用します.
次に、サーバーコンポーネントが登録され、クライアント資格情報の流れが有効になります.この流れのために、我々はトークン終点を登録する必要があります.このエンドポイントを実装する必要があります.後でこれをします.
OpenIDDictはトークンを暗号化してサインすることができるので、暗号化のためのキーと署名のために2つのキーを登録する必要があります.この例では、文字キーを使用します.アプリケーションがシャットダウンし、ペイロードが署名されたか、これらのキーを使用して暗号化されたペイロードが自動的に無効になったときに、一時的なキーが自動的に破棄されます.このメソッドは、開発中のみ使用する必要があります.X . 509証明書を使用して、生産に推薦されます.
RegisterScopes
どのスコープ(権限)がサポートされているかを定義します.この場合、1つのスコープがありますapi
, しかし、認証サーバは複数のスコープをサポートできます.The
UseAspNetCore()
コールは、OpenDictのホストとしてaspnetcoreを設定するために使用されます.また、コールEnableTokenEndpointPassthrough
それ以外の場合は、将来のトークンエンドポイントへの要求はブロックされます.OpenIDDictが正しく設定されているかどうかを確認するには、アプリケーションを起動し、次のように移動します.https://localhost:5001/.well-known/openid-configuration , レスポンスは次のようになります.
{
"issuer": "https://localhost:5001/",
"token_endpoint": "https://localhost:5001/connect/token",
"jwks_uri": "https://localhost:5001/.well-known/jwks",
"grant_types_supported": [
"client_credentials"
],
"scopes_supported": [
"openid",
"api"
],
"claims_supported": [
"aud",
"exp",
"iat",
"iss",
"sub"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"subject_types_supported": [
"public"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"claims_parameter_supported": false,
"request_parameter_supported": false,
"request_uri_parameter_supported": false
}
このガイドでは、我々は使用されますPostman 権限サーバーをテストするには、簡単に別のツールを使用することができます.以下に、Postmanを使用した例の認証要求を見つけます.Grant Typeはクライアント資格情報の流れです.クライアントを認証するために、アクセストークンURL、クライアントIDと秘密を指定します.また、アクセスを要求します
api
スコープ.トークンを要求すると、操作は失敗します.これは私たちの認証サーバをまだ登録していないからです.
データベースに追加することでクライアントを作成できます.そのためにクラスと呼ばれるクラスを作ります
TestData
. テストデータはIHostedService
におけるテストデータの生成を実行できるインターフェースStartup.cs
ときは、アプリケーションを起動します.using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenIddict.Abstractions;
namespace AuthorizationServer
{
public class TestData : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public TestData(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<DbContext>();
await context.Database.EnsureCreatedAsync(cancellationToken);
var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
if (await manager.FindByClientIdAsync("postman", cancellationToken) is null)
{
await manager.CreateAsync(new OpenIddictApplicationDescriptor
{
ClientId = "postman",
ClientSecret = "postman-secret",
DisplayName = "Postman",
Permissions =
{
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,
OpenIddictConstants.Permissions.Prefixes.Scope + "api"
}
}, cancellationToken);
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
テストデータにはクライアントが登録されている.クライアントIDと秘密を使用して、認証サーバーでクライアントを認証します.パーミッションは、このクライアントのオプションが何であるかを決定します.この場合、クライアントのクライアント資格情報の流れを使用し、トークンエンドポイントにアクセスし、クライアントに要求を許可する
api
スコープ.テストデータサービスを登録する
Startup.cs
, アプリケーションの起動時に実行されます.public void ConfigureServices(IServiceCollection services)
{
...
services.AddHostedService<TestData>();
}
Postmanで再度アクセストークンを取得しようとすると、リクエストは失敗します.これはまだトークンエンドポイントを作成していないからです.今すぐやります.新しいコントローラを作成する
AuthorizationController
, ここでエンドポイントをホストします.using System;
using System.Security.Claims;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;
using OpenIddict.Server.AspNetCore;
namespace AuthorizationServer.Controllers
{
public class AuthorizationController : Controller
{
[HttpPost("~/connect/token")]
public IActionResult Exchange()
{
var request = HttpContext.GetOpenIddictServerRequest() ??
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
ClaimsPrincipal claimsPrincipal;
if (request.IsClientCredentialsGrantType())
{
// Note: the client credentials are automatically validated by OpenIddict:
// if client_id or client_secret are invalid, this action won't be invoked.
var identity = new ClaimsIdentity(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
// Subject (sub) is a required field, we use the client id as the subject identifier here.
identity.AddClaim(OpenIddictConstants.Claims.Subject, request.ClientId ?? throw new InvalidOperationException());
// Add some claim, don't forget to add destination otherwise it won't be added to the access token.
identity.AddClaim("some-claim", "some-value", OpenIddictConstants.Destinations.AccessToken);
claimsPrincipal = new ClaimsPrincipal(identity);
claimsPrincipal.SetScopes(request.GetScopes());
}
else
{
throw new InvalidOperationException("The specified grant type is not supported.");
}
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
}
}
つのアクションが実装されます.Exchange
. このアクションは、クライアントの資格情報の流れだけでなく、すべてのフローによってアクセストークンを取得するために使用されます.クライアント資格情報フローの場合、クライアントの資格情報に基づいてトークンが発行されます.認証コードフローの場合、同じエンドポイントを使用しますが、トークンの認証コードを交換します.我々は、それを見ます.
今のところ、クライアントの資格情報の流れに集中する必要があります.リクエストが
Exchange
アクション、クライアント資格情報(clientidとclientSecret)は既にOpenIDDictによって検証されます.それで、我々は要求を認証する必要はありません、我々はクレームプリンシパルを作成しなければならなくて、サインするためにそれを使用しなければならないだけです.クレームプリンシパルは、アカウントコントローラで使用されているものと同じではありません.これは、クッキー認証ハンドラに基づいていて、認証サーバー自身のコンテキスト内でのみ使用され、ユーザーが認証されたかどうかを判断します.
我々が作成しなければならないクレームプリンシパルは
OpenIddictServerAspNetCoreDefaults.AuthenticationScheme
. このように、我々が呼ぶときSignIn
このメソッドの最後に、OpenIDDictミドルウェアは、Sign INを処理し、クライアントへの応答としてアクセストークンを返します.クレームプリンシパルで定義されたクレームは、目的地を指定するときのみアクセストークンに含まれる.The
some-value
この例ではアクセストークンにクレームを追加します.The
subject
クレームが必要であり、目的地を指定する必要はありません.また、呼び出しによってすべての要求されたスコープを付与する
claimsPrincipal.SetScopes(request.GetScopes());
. OpenIDDictは、要求されたスコープが許可されているかどうかを確認しました.スコープをここで手動で追加しなければならない理由は、ここで指定したスコープをフィルタリングすることができます.それらをすべて支配するトークン
再び郵便配達人とのアクセストークンを手に入れようとしましょう.
OpenIDDictのv 3の時点で、アクセストークンはデフォルトでJason Webトークン(JWT)形式です.これによりトークンを調べることができますjwt.io . 感謝Auth0 , そのサービスをホスティングするために!)
つの問題は、トークンが署名されていないだけでなく、暗号化されます.OpenIDDict既定でアクセストークンを暗号化します.OpenDictを設定するとき、この暗号化を無効にすることができます
Startup.cs
:// Encryption and signing of tokens
options
.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey()
.DisableAccessTokenEncryption();
さて、認証サーバーを再起動し、新しいトークンを要求するとき.トークンをペーストするjwt.io トークンの内容を表示します.クライアントIDを見ることができます
postman
が設定されるsub
. またsome-claim
クレームがアクセストークンに追加されます.次
おめでとう、あなたは
Client Credentials Flow
OpenIDdictで!お気づきのように、ログインページはクライアント資格情報の流れによって使用されません.このフローはクライアントの資格情報をすぐにトークンに交換します.
を実装します
Authorization Code Flow with PKCE
, これは、単一ページアプリケーション(SPA)とモバイルアプリケーションの推奨される流れです.この流れはユーザーを含んでいるので、我々のログインページは遊びに来ます.Reference
この問題について(OpenIDDictによる認証サーバの設定-パートIII -クライアント資格情報の流れ), 我々は、より多くの情報をここで見つけました https://dev.to/robinvanderknaap/setting-up-an-authorization-server-with-openiddict-part-iii-client-credentials-flow-55lpテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol