当用户设置为非活动时,不要在 Identity Server 4 中发出令牌

Don't issue a token in Identity Server 4 when a user is set to inactive

我们最近通过 Identity.AspNetUsers table 中的“活动”布尔字段实现了在我们的应用程序中禁用用户的功能。登录到后台系统(一个 Angular 应用程序)很容易通过隐式流程处理——只需在调用 PasswordSignInAsync.

之前检查该字段

我们无法找到一种方法来阻止使用调用内置 ID Server 4 端点的姊妹应用程序(用 Flutter 编写)为任何移动设备颁发令牌 /connect/token。同样,我们无法阻止应用程序请求并接收有效的刷新令牌。我们不能硬删除用户,因为我们有硬链接到数据库中的其他 table 以用于审计目的。

如有任何帮助,我们将不胜感激。

我们正在使用 DotNET Core 3,1。

编辑:我们正在使用密码授予类型。

当客户端使用刷新令牌请求新的访问令牌时,就会涉及到RefreshTokenService。通过自定义刷新令牌行为,您可以查找用户是否被禁用,然后拒绝颁发新的访问令牌。有关如何执行此操作的更多详细信息,请参阅此 page

或者,如果用户被禁用,您可以在实现 IPersistedGrantStore 的 class 中添加一些代码来查找,然后 return

return Task.FromResult<PersistedGrant>(null!);

被屏蔽时。

当使用内置 /connect/token 端点的密码授予时,您实现接口 ICustomTokenRequestValidator 并将其作为 Transient 添加到服务集合中。这有一种方法,ValidateAsync,如果您的请求引用的用户有效,您只需 return 并且管道将照常继续。如果您的用户无效,您将 CustomTokenRequestValidationContext 上的 Result.IsError 属性 设置为 true,并在 return 之前向 Result.Error 提供一个字符串,这样令牌就可以了未发行。

注入 UserManager<T>IHttpContextAccessor 以便您可以从该方法访问用户名和用户存储。

这是一个实现:

    public class CustomTokenRequestValidator : ICustomTokenRequestValidator
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private const string errorMessage = "invalid_username_or_password";
        public CustomTokenRequestValidator(
              UserManager<ApplicationUser> userManager
            , IHttpContextAccessor httpContextAccessor)
        {
            _userManager = userManager;
            _httpContextAccessor = httpContextAccessor;
        }
        public async Task ValidateAsync(CustomTokenRequestValidationContext context)
        {
            _httpContextAccessor.HttpContext.Request.Form.TryGetValue("username", out var userOut);
            var u = userOut.ToString();

            if(u != null)
            {
                var user = await _userManager.FindByEmailAsync(u);
                if(user == null || !user.Active)
                {
                    context.Result.IsError = true;
                    context.Result.Error = errorMessage;
                }
            } else
            {
                context.Result.IsError = true;
                context.Result.Error = errorMessage;
            }
            return;
        }
    }