如何在 Identity Server 4 中记录生成的访问令牌?

How can I log the generated Access Token in Identity Server 4?

我想知道如何在 IdentityServer 4 中记录生成的 Refresh 和 AccessToken。

目前,我们已经获得了关于 JwtAccessToken 的自定义实现,每当它生成新的访问令牌时,我们都会将其写入 + userId/name 到中央日志系统。对于 Apis(我们有超过 10 个),它总是将所有传入请求 + JwtToken 写入同一个日志系统。因此,我们可以很容易地跟踪用户在那个特定时间做了什么并查看 logs/values。

现在,我们将用 IDSV4 替换该自定义安全实现,但我们找不到在 IDSV4 中记录生成的令牌的方法。

我们知道可以通过await HttpContext.GetAccessTokenAsync()获取.Net App中的Access Token。但我们不想从所有将与 IDSV 集成的应用程序(.Net、Spas、Apis(客户端凭据))手动发送日志。我们想像以前一样在一个中心位置管理 AccessToken 日志记录。

我看了IDSV4源码TokenEndpoint.cs第120行,LogTokens()

if (response.IdentityToken != null)
            {
                _logger.LogTrace("Identity token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.IdentityToken);
            }
            if (response.RefreshToken != null)
            {
                _logger.LogTrace("Refresh token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.RefreshToken);
            }
            if (response.AccessToken != null)
            {
                _logger.LogTrace("Access token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.AccessToken);
            }

实际上,他们为实际令牌编写了 TraceLogs。但是我们不想将日志级别更新为 Trace,因为它会淹没我们的日志系统。

所以,我想知道是否可以实现一项功能,以便在 IDSV4 发出 AccessToken 时将生成的令牌写入日志。生成之后有没有办法拦截这些token?

或者我们是否必须在所有客户端生成或刷新 AccessTokens 时手动记录它?

更新: 感谢 sellotape 给了我 DI 的想法。下面是正确的class拦截生成的Token:

public class CustomTokenResponseGenerator : TokenResponseGenerator
    {
        public CustomTokenResponseGenerator(ISystemClock clock, ITokenService tokenService, IRefreshTokenService refreshTokenService, IResourceStore resources, IClientStore clients, ILogger<TokenResponseGenerator> logger) : base(clock, tokenService, refreshTokenService, resources, clients, logger)
        {
        }

        public override async Task<TokenResponse> ProcessAsync(TokenRequestValidationResult request)
        {
            var result = await base.ProcessAsync(request);
            // write custom loggings here
            return result;
        }
    }

之后,您可以将 IDSV4 中的默认 class 替换为您自定义的 class

services.Replace(ServiceDescriptor.Transient<ITokenResponseGenerator, CustomTokenResponseGenerator>());

有很多地方可以挂钩;一种是通过派生自 DefaultTokenService.

创建您自己的 ITokenService 实现

覆盖 CreateAccessTokenAsync() 并让它执行:

Token result = await base.CreateAccessTokenAsync(request);
// Your logging goes here...
return result;

启动时在 DI 容器中换入你的版本(确保它是在默认版本已经添加之后):

services.Replace<ITokenService, MyTokenService>();

...你应该准备好了。


顺便说一句,你真的应该记录你的令牌的散列,而不是令牌本身。您仍然可以根据哈希将请求和操作与用户匹配,但至少没有人能够使用日志记录数据来冒充您的任何用户。