如何让 Angular Client 通知 Identity Server 使用哪种登录方式?

How to make Angular Client to inform Identity Server which login method to use?

我将 IdentityServer 4 与 Angular 10 客户端一起使用,该客户端使用 OIDC Client JS:

要重定向用户登录,我在 Angular 的客户端上调用 signinRedirect:

UserManager.signinRedirect(args)

重定向到 IdentityServer 4 AcccountController's Login 操作:

[HttpGet]
public async Task<IActionResult> Login(string returnUrl) {
  var vm = await BuildLoginViewModelAsync(returnUrl);
  if (vm.IsExternalLoginOnly) {
    // we only have one option for logging in and it's an external provider
    return RedirectToAction("Challenge", "External", new { scheme = vm.ExternalLoginScheme, returnUrl });
  }
  return View(vm);
}

问题

我在 Identity Server 中配置了 Google 和 Facebook 外部提供商。

如何使用 signinRedirect 并通知 IdentityServer 使用外部提供商,如 Google 进行登录?

我想绕过 IdentityServer 中的登录页面,其中有 3 个选项:

  1. 使用用户名和密码登录
  2. 使用 Google
  3. 登录
  4. 使用 Facebook 登录

因此 Angular 客户端会通知 Identity Server 应使用哪种登录方法。

更新

经过一些研究,规范中似乎有一种方法可以为用户指定哪个提供商:

UserManager.signinRedirect({ acr_values: 'IdP:Google' }));

然后在 AccountController's BuildLoginViewModelAsync 上有以下内容:

var context = await _interactionService.GetAuthorizationContextAsync(returnUrl);

if (request?.IdP != null && await _schemeProvider.GetSchemeAsync(request.IdP) != null) {

  var local = request.IdP == IdentityServer4.IdentityServerConstants.LocalIdentityProvider;

如果我没记错 IF 条件和以下代码是检查应使用哪个登录提供程序:本地或配置的外部提供程序之一。

我调试了 context 并得到以下信息:

已解析 AcrValues,但未定义 属性 IdP。

AcrValues 不应该是解决这个问题的方法吗?我错过了什么?

通过使用 signinRedirect 方法的 args 参数,可以使用 oidc-client 向身份提供者发送消息。

如果您从他们的 github 存储库查看 oidc-client-js/src/SigninRequest.js,您会发现您可以为上述方法提供以下可选参数:

  • data,
  • prompt,
  • display,
  • max_age,
  • ui_locales,
  • id_token_hint,
  • login_hint,
  • acr_values,
  • resource,
  • response_mode,
  • request,
  • request_uri,
  • extraQueryParams,
  • request_type,
  • client_secret,
  • extraTokenParams,
  • skipUserInfo

在代码的后面,在这个文件版本的第 75 行,他们有这个:

for(let key in extraQueryParams){
  url = UrlUtility.addQueryParam(url, key, extraQueryParams[key])
}

这意味着他们允许开发人员使用 extraQueryParams 来提供自定义参数。

现在假设您的自定义消息参数可能被称为 useExternalProvider,您应该能够像这样调用 signInRedirect

UserManager.signinRedirect({ 
  extraQueryParams: {
    useExternalProvider: "google"
  }});

要在您的 IdentityServer 上访问此参数,找到调用 GetAuthorizationContextAsync 的行并检查协议消息参数,如下所示:

var context = await interaction.GetAuthorizationContextAsync(returnUrl);
var externalProviderToUse = context.Parameters.Get("useExternalProvider");

如果您使用他们的 QuickStart,通常在 BuildLoginViewModelAsync(string returnUrl) 方法中。

从那里你可以从数据库中检索外部登录参数,或者从你保存这些参数的任何地方,而不是将用户重定向到登录页面,使用 [=39] 将他们直接重定向到你的 ExternalLogin(string provider, string returnUrl) =].

编辑

如果你想为此使用 acr_values 参数,稍后在 IdentityServer 授权上下文中想要使用 Idp 属性,你可以调用:

// "idp:" is case sensitive
UserManager.signinRedirect({ acr_values: 'idp:Google' }));