【问题标题】:How can I revoke Reference Tokens for blocking users?如何撤销用于阻止用户的参考令牌?
【发布时间】:2019-08-03 03:11:58
【问题描述】:

我有一个 Identity Server 4 的实现,它使用 Entity Framework Core 进行持久存储,使用 ASP.NET Core Identity 进行用户管理。由于此 IDS 将支持公共应用程序,我们被要求添加一种完全阻止用户的方法 - 这意味着不允许他们登录并删除他们现有的登录名。

经过长期研究,我确定 IDS 不支持过期访问令牌之类的东西,因为这不是 OpenID Connect 的一部分。让我感到完全奇怪的是,我将客户端切换为使用引用令牌,这些令牌正确存储在 PersistedGrants 表中,但即使清除该表也不会使未来的请求无效,因为用户仍然通过客户端应用程序和到身份服务器本身。

我可以重新实施任何商店/服务来阻止给定登录用户的所有访问吗?

【问题讨论】:

  • 您是如何确定访问令牌不支持过期的? IDS4 问题的开箱即用 JWT 是短期访问令牌,还可以选择获取刷新令牌。另外,如果您使用的是引用令牌,那么受 IDS4 保护的 api 资源需要启用自省,
  • @VidmantasBlazevicius 我不是说访问令牌不会过期,而是你不能强制它们过期
  • 啊,很公平,这很有道理,你能解释一下如果你使用引用令牌,这些请求是如何仍然有效的吗?你的客户端和你的api是什么类型的应用程序?
  • @VidmantasBlazevicius 对于第一个测试,我使用带有 OIDC-JS 库的 Angular 客户端针对 2 个 ASP.NET Core API 资源,其中一个托管在 IDS 应用程序中
  • 好的,所以你的 Angular 客户端存储了引用令牌并在 api 请求标头中使用它。然后,您的 Api 资源应尝试使用自省端点 /connect/introspect 每次自省参考令牌。你能检查 IDS4 日志并验证这是否正在发生吗?如果没有自省端点告诉其有效并将其交换为访问令牌,引用令牌应该是无用的。

标签: c# identityserver4


【解决方案1】:

您还必须清除 cookie。

但您可能想研究一种不同的方法。其中 IdentityServer 用作身份验证服务,授权外包,如PolicyServer

通过这种方式,您可以选择加入授权,从而降低用户仍然通过身份验证的重要性。

【讨论】:

  • 我无法清除 cookie,因为 1) 并不总是有 cookie(JWT 令牌不需要存储在 cookie 中)和 2) 我是阻止用户的管理员,而不是阻止自己的用户.但我会调查第二点
  • @CamiloTerevinto 这取决于客户。只要客户端认为用户已获得授权并且不使用 IdentityServer 进行验证,您就无能为力。这是客户的责任。但是在访问令牌方面,您可以使用引用令牌或短期 JWT,其中有一个小窗口,用户仍然可以访问资源。但是一旦需要更新令牌,就可以拒绝访问。
  • "...您可以使用引用令牌或短期 JWT..." 我的问题的标题明确指代引用令牌,正文解释了为什么我从访问令牌切换到引用令牌.这些不应该总是检查 IDS 吗?
  • 在某些时候,但不是一直。假设我有一个仅使用 cookie 的网站(并且没有一些后台 api),那么我在哪里需要访问令牌?在 cookie 过期之前,用户保持授权状态。当我添加 api 时,只要访问令牌存在,用户就可以访问 api。如果没有刷新,访问被拒绝,检查this问题。来自文档:接收此引用的 API 然后必须打开与 IdentityServer 的反向通道通信以验证令牌。
  • 作为documented API 应该验证令牌,但是当调用客户端(作为资源)时,客户端应该添加它自己的实现(例如中间件)来验证令牌。
【解决方案2】:

最后,问题在于有人将 AccessTokenType 从 1 更改回 0,因为另一个 API 不起作用,因为它被配置为使用访问令牌而不是引用令牌。感谢@VidmantasBlazevicius 指出了查看日志以查找对connect/introspect 端点的调用的正确方向。

作为参考,这是我们最终使用的代码(由管理员用户调用,适当保护):

[HttpPut("{userId}/Block")]
public async Task<IActionResult> BlockUser(string userId)
{
    var user = await _context.Users.FindAsync(userId);

    if (user == null || !user.LockoutEnabled || user.LockoutEndDate > DateTime.Now)
    {
        return BadRequest();
    }

    var currentTokens = await _context.PersistedGrants
        .Where(x => x.SubjectId == user.UserId)
        .ToArrayAsync();

    _context.PersistedGrants.RemoveRange(currentTokens);

    var newLockOutEndDate = DateTime.Now + TimeSpan.FromMinutes(_options.LockOutInMinutes);
    user.LockoutEndDate = newLockOutEndDate;

    string updater = User.Identity.Name;
    user.UpdateTime(updater);

    await _context.SaveChangesAsync();

    return NoContent();
}

【讨论】:

  • 不要忘记在 PersistedGrants 表的 SubjectId 列上放置一个索引(如果使用数据库)。
  • IPersistedGrantService 支持使用 RemoveAllGrantsAsync(user.Id.ToString()) 方法。
猜你喜欢
  • 1970-01-01
  • 2018-12-07
  • 2018-09-21
  • 1970-01-01
  • 2014-03-26
  • 2020-06-02
  • 2015-11-02
  • 2017-06-15
相关资源
最近更新 更多