基于IdentityServer4的审计字段设计:如何同时审计用户与非用户?
解决方案
针对用户/非用户场景审计、以及用户名变更的问题,给出以下可行方案,均无需回溯修改历史审计记录:
方案一:修改审计字段为「主体标识+类型」模式
数据库结构调整
将原有的用户ID审计字段替换为通用主体标识和类型,示例SQL结构:
-- 替换原CreatedByUserId/UpdatedByUserId CreatedBySubjectId VARCHAR(255) NOT NULL -- 存储唯一标识:用户用sub(用户ID),客户端用client_id,服务用专属ServiceId CreatedByType TINYINT NOT NULL -- 枚举值:1=用户,2=客户端,3=服务 CreatedDateTime DATETIME NOT NULL UpdatedBySubjectId VARCHAR(255) NOT NULL UpdatedByType TINYINT NOT NULL UpdatedDateTime DATETIME NOT NULL
填充逻辑
- 用户操作:从access token的
sub声明取CreatedBySubjectId,类型设为「用户」 - Client Credentials调用:从token的
client_id声明取CreatedBySubjectId,类型设为「客户端」 - 自动更新任务:给任务分配固定唯一的
ServiceId(比如AutoUpdateTask_ServiceX),填充到CreatedBySubjectId,类型设为「服务」
展示逻辑
应用页面展示时,根据CreatedByType动态查询对应数据源的最新名称:
- 用户:关联用户表,取当前用户名(即使改名,直接拉最新值)
- 客户端:关联IdentityServer的
Clients表,取ClientName - 服务:关联内部服务注册表,取服务的显示名称
方案二:新增审计主体映射表(适合复杂场景)
如果需要统一管理所有审计主体的显示名称,可新增一张AuditSubject表:
CREATE TABLE AuditSubject ( SubjectId VARCHAR(255) NOT NULL PRIMARY KEY, SubjectType TINYINT NOT NULL, DisplayName VARCHAR(255) NOT NULL, UpdatedDateTime DATETIME NOT NULL )
逻辑说明
- 当用户改名、客户端/服务名称变更时,仅更新
AuditSubject表中对应记录的DisplayName - 原实体的审计字段存储
SubjectId和SubjectType,展示时直接关联AuditSubject表取当前名称 - 优势:无需跨多表查询,可对
AuditSubject做缓存优化,提升展示性能
关键注意事项
- 绝对不要存储静态用户名/客户端名称:这类信息可能变更,会导致历史审计记录展示失效,必须通过唯一标识动态拉取最新名称
- 自动任务的身份标识:给每个自动任务分配固定、唯一的
ServiceId,不要用易变的名称,确保审计溯源的准确性 - 中间件适配:修改原数据库中间件的填充逻辑,支持解析不同类型token的声明(用户的
sub、客户端的client_id),以及识别自动任务的上下文
内容的提问来源于stack exchange,提问作者Logan Cooper
相关产品推荐
相关产品推荐

