audit_hooks.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package auth
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/kairo/haven/internal/audit"
  5. )
  6. // UseAudit 把审计写入器接到 Handler 的各个钩子上。
  7. //
  8. // 依据 docs/backend/audit.md:事件在业务成功后写,失败只记日志,
  9. // 因此这些钩子内部不返回错误、不影响响应。
  10. func UseAudit(h *Handler, w *audit.Writer) {
  11. if w == nil {
  12. return
  13. }
  14. record := func(c *gin.Context, e audit.Event) {
  15. w.Record(c.Request.Context(), e)
  16. }
  17. h.OnLoginSuccess = func(c *gin.Context, e LoginAudit) {
  18. record(c, audit.Event{
  19. ActorUserID: e.UserID,
  20. ActorUsername: e.Username,
  21. EventType: audit.EventLoginSuccess,
  22. Metadata: map[string]any{"via": e.Via},
  23. IP: c.ClientIP(),
  24. UserAgent: c.Request.UserAgent(),
  25. })
  26. }
  27. h.OnLoginFailure = func(c *gin.Context, username, reason string) {
  28. record(c, audit.Event{
  29. ActorUsername: username,
  30. EventType: audit.EventLoginFailure,
  31. Metadata: map[string]any{"reason": reason},
  32. IP: c.ClientIP(),
  33. UserAgent: c.Request.UserAgent(),
  34. })
  35. }
  36. h.OnLogout = func(c *gin.Context, ac AuditContext) {
  37. record(c, audit.Event{
  38. ActorUserID: ac.UserID,
  39. ActorUsername: ac.Username,
  40. EventType: audit.EventLogout,
  41. IP: ac.IP,
  42. UserAgent: ac.UA,
  43. })
  44. }
  45. h.OnTotpBound = func(c *gin.Context, ac AuditContext) {
  46. record(c, audit.Event{
  47. ActorUserID: ac.UserID,
  48. ActorUsername: ac.Username,
  49. EventType: audit.EventTotpBound,
  50. TargetType: audit.TargetUser,
  51. TargetID: ac.UserID,
  52. IP: ac.IP,
  53. UserAgent: ac.UA,
  54. })
  55. }
  56. h.OnTotpDisabled = func(c *gin.Context, ac AuditContext) {
  57. record(c, audit.Event{
  58. ActorUserID: ac.UserID,
  59. ActorUsername: ac.Username,
  60. EventType: audit.EventTotpDisabled,
  61. TargetType: audit.TargetUser,
  62. TargetID: ac.UserID,
  63. IP: ac.IP,
  64. UserAgent: ac.UA,
  65. })
  66. }
  67. h.OnPasswordChanged = func(c *gin.Context, ac AuditContext) {
  68. record(c, audit.Event{
  69. ActorUserID: ac.UserID,
  70. ActorUsername: ac.Username,
  71. EventType: audit.EventPasswordChanged,
  72. TargetType: audit.TargetUser,
  73. TargetID: ac.UserID,
  74. IP: ac.IP,
  75. UserAgent: ac.UA,
  76. })
  77. }
  78. h.OnTrustedDeviceAdd = func(c *gin.Context, ac AuditContext, deviceName string) {
  79. record(c, audit.Event{
  80. ActorUserID: ac.UserID,
  81. ActorUsername: ac.Username,
  82. EventType: audit.EventTrustedDeviceAdded,
  83. TargetType: audit.TargetTrustedDevice,
  84. Metadata: map[string]any{"device_name": deviceName},
  85. IP: ac.IP,
  86. UserAgent: ac.UA,
  87. })
  88. }
  89. h.OnSessionRevoked = func(c *gin.Context, ac AuditContext, sessionID, createdAt string) {
  90. record(c, audit.Event{
  91. ActorUserID: ac.UserID,
  92. ActorUsername: ac.Username,
  93. EventType: audit.EventSessionRevoked,
  94. TargetType: audit.TargetSession,
  95. TargetID: sessionID,
  96. Metadata: map[string]any{"session_created_at": createdAt},
  97. IP: ac.IP,
  98. UserAgent: ac.UA,
  99. })
  100. }
  101. h.OnDeviceRevoked = func(c *gin.Context, ac AuditContext, deviceName string) {
  102. record(c, audit.Event{
  103. ActorUserID: ac.UserID,
  104. ActorUsername: ac.Username,
  105. EventType: audit.EventTrustedDeviceRevoke,
  106. TargetType: audit.TargetTrustedDevice,
  107. Metadata: map[string]any{"device_name": deviceName},
  108. IP: ac.IP,
  109. UserAgent: ac.UA,
  110. })
  111. }
  112. h.OnTokenCreated = func(c *gin.Context, ac AuditContext, name, scope, prefix string) {
  113. record(c, audit.Event{
  114. ActorUserID: ac.UserID,
  115. ActorUsername: ac.Username,
  116. EventType: audit.EventTokenCreated,
  117. TargetType: audit.TargetToken,
  118. // audit.md 第三节:metadata 不含明文
  119. Metadata: map[string]any{"name": name, "scope": scope, "token_prefix": prefix},
  120. IP: ac.IP,
  121. UserAgent: ac.UA,
  122. })
  123. }
  124. h.OnTokenRevoked = func(c *gin.Context, ac AuditContext, name, prefix string) {
  125. record(c, audit.Event{
  126. ActorUserID: ac.UserID,
  127. ActorUsername: ac.Username,
  128. EventType: audit.EventTokenRevoked,
  129. TargetType: audit.TargetToken,
  130. Metadata: map[string]any{"name": name, "token_prefix": prefix},
  131. IP: ac.IP,
  132. UserAgent: ac.UA,
  133. })
  134. }
  135. }
苏ICP备2026082406号
苏公网安备 待审核