【问题标题】:How to retrieve Parameters set on AuthenticationProperties in IdentityServer4 OIDC challenge?如何在 IdentityServer4 OIDC 质询中检索在 AuthenticationProperties 上设置的参数?
【发布时间】:2019-05-23 22:24:29
【问题描述】:

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

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

我已经通过 IdentityServer4 端的代码进行了本地和外部回调的登录,returnUrl 永远不会出现在那里。我假设 OIDC StateDataFormatterCache 会拦截它以防止潜在的长 url 问题,并且应该拦截响应并注入返回 url。那部分似乎不起作用,所以我试图看看我是否可以将我自己的自定义参数粘贴到 auth 道具中,并在 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

以下是 Redis 中显示的内容:

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

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

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

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

【问题讨论】:

标签: c# identityserver4


【解决方案1】:

这种行为是设计使然,除了持久化到 Redis。 Parameters 上的评论说:

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

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

//configuration
services.AddOidcStateDataFormatterCache(Constants.MyExternalIdIdpName);
//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);
}

然后

[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("~/");
}

【讨论】:

  • 看起来差不多,但是AuthenticationProperties的构造方式并没有在原帖中列出
  • 我更新了AuthenticationProperties 是如何构造的
猜你喜欢
  • 2021-06-02
  • 2023-03-25
  • 1970-01-01
  • 2018-03-02
  • 2021-10-02
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 2021-06-05
相关资源
最近更新 更多