feat(auth): implement session-based token management with revocation support
All checks were successful
Build Backend / build (push) Successful in 2m19s
Build Backend / build-docker (push) Successful in 46s

Add Session model, SessionService, and SessionRepository to track user login
sessions and enable token revocation on auth-critical events.

- Introduce explicit TokenType (access/refresh) in JWT claims to prevent
  refresh token misuse via access token endpoints
- Add SessionID field to JWT claims, enabling stateless JWT validation
  against revoked sessions
- Replace legacy Auth middleware with RequireAuth/OptionalAuth pipeline
  that validates token type, account status, and session validity
- Implement session revocation on password change, reset, user ban/inactive,
  and explicit logout
- Add Principal cache with active invalidation for banned/role-changed users
- Fix IDOR vulnerability: GetMessagesByCursor now validates currentUserID
  is conversation participant via GetParticipantStrict
- Add group member visibility checks: announcements, group info, member list
  now require group membership
- Simplify Casbin policy: remove g grouping, use r.sub == p.sub matcher
  with globMatch; user_roles table is single source of truth for roles
- Add migration logic to clean legacy casbin g rules and migrate old p rules
  from path-style to admin/<domain> resource naming
This commit is contained in:
lafay
2026-07-05 18:28:08 +08:00
parent d240485d0e
commit eb931bf1c6
41 changed files with 2544 additions and 360 deletions

View File

@@ -28,6 +28,9 @@ var ServiceSet = wire.NewSet(
// JWT 服务(需要配置参数)
ProvideJWTService,
// 会话服务(令牌撤销支持)
ProvideSessionService,
// 基础服务
ProvideEmailService,
ProvidePostAIService,
@@ -97,6 +100,14 @@ func ProvideJWTService(cfg *config.Config) service.JWTService {
)
}
// ProvideSessionService 提供会话服务(用于令牌撤销)。
func ProvideSessionService(
sessionRepo repository.SessionRepository,
jwtService service.JWTService,
) service.SessionService {
return service.NewSessionService(sessionRepo, jwtService)
}
// ProvideEmailService 提供邮件服务
func ProvideEmailService(client email.Client) service.EmailService {
return service.NewEmailService(client)
@@ -180,8 +191,9 @@ func ProvideUserService(
emailService service.EmailService,
cacheBackend cache.Cache,
logService *service.LogService,
sessionService service.SessionService,
) service.UserService {
return service.NewUserService(userRepo, systemMessageService, emailService, cacheBackend, logService)
return service.NewUserService(userRepo, systemMessageService, emailService, cacheBackend, logService, sessionService)
}
// ProvideStickerService 提供表情服务
@@ -222,6 +234,7 @@ func ProvideChatService(
redisClient *redis.Client,
versionLogRepo repository.ConversationVersionLogRepository,
cfg *config.Config,
groupService service.GroupService,
) service.ChatService {
var vlogOpt []repository.ConversationVersionLogRepository
if cfg.VersionLog.Enabled {
@@ -231,7 +244,9 @@ func ProvideChatService(
if redisClient != nil {
rdb = redisClient.GetClient()
}
return service.NewChatService(messageRepo, userRepo, nil, publisher, cacheBackend, uploadService, pushService, seqBufferMgr, pushWorker, rdb, vlogOpt...)
// 注入 GroupAbility群消息发送前校验成员/禁言。
groupAbility := service.NewGroupAbility(groupService)
return service.NewChatService(messageRepo, userRepo, nil, publisher, cacheBackend, uploadService, pushService, seqBufferMgr, pushWorker, rdb, groupAbility, vlogOpt...)
}
// ProvideScheduleService 提供日程服务
@@ -340,8 +355,14 @@ func ProvideRoleService(
}
// ProvideAdminUserService 提供管理端用户服务
func ProvideAdminUserService(userRepo repository.UserRepository) service.AdminUserService {
return service.NewAdminUserService(userRepo)
//
// 注入 SessionService 与 cache封禁/停用用户时撤销其全部登录会话并失效 Principal 缓存。
func ProvideAdminUserService(
userRepo repository.UserRepository,
sessionService service.SessionService,
cacheBackend cache.Cache,
) service.AdminUserService {
return service.NewAdminUserService(userRepo, sessionService, cacheBackend)
}
// ProvideAdminPostService 提供管理端帖子服务