Sign-in with External Identity Providers¶
ASP.NETコアは、外部認証に柔軟に対応します。これにはいくつかのステップが必要です。
注釈
ASP.NET IDを使用している場合、基礎となる技術的詳細の多くはあなたから隠されています。また、Microsoftのドキュメントを読み、ASP.NET IDのクイックスタートを行うことをお勧めします。
外部プロバイダの認証ハンドラの追加¶
外部プロバイダと通信するために必要なプロトコル実装は、認証ハンドラにカプセル化されています。一部のプロバイダは独自のプロトコル(Facebookなどのソーシャルプロバイダなど)を使用しており、一部のプロトコルではOpenID Connect、WS-Federation、SAML2pなどの標準プロトコルを使用しています。
外部認証を追加して構成する手順については、このクイックスタートを参照してください。
クッキーの役割¶
外部認証ハンドラの1つのオプションが呼び出されますSignInScheme。例:
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = "scheme of cookie handler to use";
options.ClientId = "...";
options.ClientSecret = "...";
})
サインイン方式は、外部プロバイダの結果を一時的に保存するクッキーハンドラの名前を指定します。通常、外部認証プロセスを完了するまで、数回のリダイレクトが行われるため、これは必要です。
これがあまり一般的でない場合、IdentityServerはこの外部プロバイダワークフロー専用のCookieハンドラを登録します。スキームはIdentityServerConstants.ExternalCookieAuthenticationScheme定数によって表されます。外部のCookieハンドラを使用する場合は、SignInScheme上記の値をIdentityServerConstants.ExternalCookieAuthenticationScheme定数に割り当てます。
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "...";
options.ClientSecret = "...";
})
次のように独自のカスタムCookieハンドラを登録することもできます。
services.AddAuthentication()
.AddCookie("YourCustomScheme")
.AddGoogle("Google", options =>
{
options.SignInScheme = "YourCustomScheme";
options.ClientId = "...";
options.ClientSecret = "...";
})
注釈
特別なシナリオでは、外部のCookieメカニズムを短絡し、外部のユーザーをメインのCookieハンドラに直接転送することもできます。これには通常、外部ハンドラでイベントを処理して、外部IDソースから正しいクレーム変換を実行する必要があります。
認証ハンドラのトリガ¶
(またはMVCを使用して)ChallengeAsync拡張メソッドをHttpContext使用して外部認証ハンドラを呼び出しChallengeResultます。
通常、コールバックページへのパスや簿記のプロバイダ名など、チャレンジ操作にいくつかのオプションを渡します。
var callbackUrl = Url.Action("ExternalLoginCallback");
var props = new AuthenticationProperties
{
RedirectUri = callbackUrl,
Items =
{
{ "scheme", provider },
{ "returnUrl", returnUrl }
}
};
return Challenge(provider, props);
コールバックの処理とユーザのサインイン¶
コールバックページでは、一般的なタスクは次のとおりです。
- 外部プロバイダから返されたIDを調べます。
- そのユーザーに対処する方法を決定します。これは、新規ユーザーまたは再帰ユーザーの場合は、これが実際の状況に基づいて異なる可能性があります。
- 新しいユーザーは、許可される前に追加の手順とUIが必要になることがあります。
- おそらく外部プロバイダーにリンクされている新しい内部ユーザーアカウントを作成します。
- 保管したい外部クレームを保管してください。
- 一時的なクッキーを削除する
- ユーザーにサインインする
外部IDの検査
// read external identity from the temporary cookie
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
if (result?.Succeeded != true)
{
throw new Exception("External authentication error");
}
// retrieve claims of the external user
var externalUser = result.Principal;
if (externalUser == null)
{
throw new Exception("External authentication error");
}
// retrieve claims of the external user
var claims = externalUser.Claims.ToList();
// try to determine the unique id of the external user - the most common claim type for that are the sub claim and the NameIdentifier
// depending on the external provider, some other claim type might be used
var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
if (userIdClaim == null)
{
userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
}
if (userIdClaim == null)
{
throw new Exception("Unknown userid");
}
var externalUserId = userIdClaim.Value;
var externalProvider = userIdClaim.Issuer;
// use externalProvider and externalUserId to find your user, or provision a new user
クリーンアップとサインイン:
// issue authentication cookie for user
await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, props, additionalClaims.ToArray());
// delete temporary cookie used during external authentication
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
// validate return URL and redirect back to authorization endpoint or a local page
if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return Redirect("~/");
State, URL length, and ISecureDataFormat¶
サインインのために外部プロバイダーにリダイレクトするとき、クライアントアプリケーションからの頻繁な状態は往復する必要があります。これは、クライアントを離れる前に状態がキャプチャされ、ユーザーがクライアントアプリケーションに戻るまで保持されることを意味します。OpenID Connectを含む多くのプロトコルは、要求の一部としてパラメータとして何らかの状態を渡すことを許可し、アイデンティティプロバイダはその状態を応答に返します。ASP.NET Coreによって提供されるOpenID Connect認証ハンドラは、このプロトコルの機能を利用しており、これがreturnUrl上記の機能を実装する方法です。
リクエストパラメータに状態を格納する際の問題は、リクエストURLが(2000文字の共通の制限を超えて)大きくなりすぎる可能性があることです。OpenID Connect認証ハンドラは、リクエストURLではなくサーバに状態を保存するための拡張ポイントを提供します。OpenIdConnectOptionsISecureDataFormat<AuthenticationProperties>で実装して設定することで、これを実装することができます。
幸いにも、IdentityServerはIDistributedCache、DIコンテナ(標準などMemoryDistributedCache)に登録されている実装に基づいて、この実装を提供します。IdentityServerが提供する安全なデータフォーマットの実装を使用するには、DIを設定AddOidcStateDataFormatterCacheするIServiceCollectionときに拡張メソッドを呼び出します。パラメータが渡されない場合、設定されたすべてのOpenID Connectハンドラは、IdentityServerが提供する安全なデータフォーマットの実装を使用します。
public void ConfigureServices(IServiceCollection services)
{
// configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache.
services.AddOidcStateDataFormatterCache();
services.AddAuthentication()
.AddOpenIdConnect("demoidsrv", "IdentityServer", options =>
{
// ...
})
.AddOpenIdConnect("aad", "Azure AD", options =>
{
// ...
})
.AddOpenIdConnect("adfs", "ADFS", options =>
{
// ...
});
}
特定のスキームのみを設定する場合は、それらのスキームをパラメータとして渡します。
public void ConfigureServices(IServiceCollection services)
{
// configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache.
services.AddOidcStateDataFormatterCache("aad", "demoidsrv");
services.AddAuthentication()
.AddOpenIdConnect("demoidsrv", "IdentityServer", options =>
{
// ...
})
.AddOpenIdConnect("aad", "Azure AD", options =>
{
// ...
})
.AddOpenIdConnect("adfs", "ADFS", options =>
{
// ...
});
}