如何检索 IdentityServer4 OIDC 质询中 AuthenticationProperties 上设置的参数?

Dar*_*ord 5 c# identityserver4

我将 IdentityServer4 作为身份验证系统运行,以使用 Google 和 Amazon 以及本地帐户。我有一个单独的网络应用程序,使用 IdentityServer4 系统作为 oidc 身份验证提供程序,并且似乎可以进行身份​​验证和颁发令牌。问题是它在身份验证后不维护 returnUrl。我正在使用通过 Redis 分布式缓存内置到 Id4 的 OIDC StateDataFormatterCache,并在 Redis 中验证它正在写入重定向,甚至是我在挑战时添加的测试参数。

身份验证后,它不会将我重定向回原始网址,并且当我尝试访问质询中设置的参数和 AuthenticationProperties 时,它们在身份验证后似乎不存在。

我已经单步执行了 IdentityServer4 端的代码,其中本地和外部回调的登录信息以及 returnUrl 从未显示在那里。我假设 OIDC StateDataFormatterCache 拦截此行为是为了防止潜在的长 url 问题,并且应该拦截响应并注入返回 url。这部分似乎不起作用,所以我试图看看是否可以将自己的自定义参数粘贴到 auth props 中,并在 auth 发生后将其取出,但结果是空的。AuthenticationProperties 似乎只有 access_token、refresh_token、id_token 等,但缺少重定向 url 和我的自定义参数。

services.AddOidcStateDataFormatterCache("oidc");
...
var authProps = new AuthenticationProperties { RedirectUri = originalPath + context.Request.QueryString };

Microsoft.Extensions.Primitives.StringValues stateValue;

if (context.Request.Query.TryGetValue("state", out stateValue))
{
   authProps.SetParameter("itk", stateValue);
}

await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.ChallengeAsync(context,"oidc", authProps); //authProps has custom parameter 'itk' and a redirect
...
var authContext = await context.AuthenticateAsync("oidc");
//authContext.Properties has data but not the RedirectUri or the custom parameter I set and verified to exist in the redis store
Run Code Online (Sandbox Code Playgroud)

以下是 Redis 中显示的内容:

{
  "Items": {
    ".redirect": "/?state=foo",
    ".xsrf": "DkRjG29eE4qDFaNLSktyTDKfhdzXH8FfVpAwBbje6tc",
    "OpenIdConnect.Code.RedirectUri": "https://localhost/signin-oidc"
  },
  "Parameters": {
    "itk": [
      "foo"
    ]
  },
  "RedirectUri": "/?state=foo"
}
Run Code Online (Sandbox Code Playgroud)

关于为什么我无法检索状态数据格式化程序放入 Redis 的信息有什么想法吗?

我需要能够获取参数中“itk”的值。

我发现重定向未通过的问题,但我仍然需要能够获取该参数。

d_f*_*d_f 2

该行为是设计使然,除了持久化到 Redis 之外。评论里说Parameters:

传递给身份验证处理程序的参数集合。它们不适用于序列化或持久性,仅用于在调用站点之间流动数据。

我们必须使用Items集合来进行序列化或持久化。
它对我有用的方式:

//configuration
services.AddOidcStateDataFormatterCache(Constants.MyExternalIdIdpName);
Run Code Online (Sandbox Code Playgroud)
//AccountController
[HttpGet]
public IActionResult Login(string returnUrl)
{
  string provider = Constants.MyExternalIdIdpName;
  string returnUrl2 = Url.Action("ExternalLoginCallback", new { returnUrl = returnUrl });

  // start challenge and roundtrip the return URL
  var props = new AuthenticationProperties
  {
    RedirectUri = returnUrl2,
    Items = { { "scheme", provider } }
  };

  return new ChallengeResult(provider, props);
}
Run Code Online (Sandbox Code Playgroud)

进而

[HttpGet]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
  // read external identity from the temporary cookie
  var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

  // retrieve claims of the external user
  var claims = result.Principal.Claims.ToList();

  var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
  var user = <users>.FindByExternalProvider(provider, userIdClaim.Value);

  await _events.RaiseAsync(new UserLoginSuccessEvent(provider, userId, user.SubjectId, user.Username));
  await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, props, additionalClaims.ToArray());

  // delete temporary cookie used during external authentication
  await HttpContext.SignOutAsync(IdentityServer4.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("~/");
}
Run Code Online (Sandbox Code Playgroud)