From b9dff99d63e05cf7c9049b37aca110dc7cf8a420 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Wed, 27 May 2026 13:44:14 +0800 Subject: [PATCH] feat: add login user display to login records (#12870) --- core/app/api/v2/auth.go | 22 ++++++++++++++++++---- core/app/dto/logs.go | 3 ++- core/app/model/logs.go | 1 + core/app/repo/logs.go | 10 +++++++--- core/app/service/logs.go | 4 ++-- core/cmd/server/docs/docs.go | 2 +- core/cmd/server/docs/swagger.json | 2 +- core/init/migration/migrate.go | 1 + core/init/migration/migrations/init.go | 7 +++++++ frontend/src/api/interface/log.ts | 3 ++- frontend/src/views/log/login/index.vue | 10 +++++++--- 11 files changed, 49 insertions(+), 16 deletions(-) diff --git a/core/app/api/v2/auth.go b/core/app/api/v2/auth.go index dde64a2db..2839e40a2 100644 --- a/core/app/api/v2/auth.go +++ b/core/app/api/v2/auth.go @@ -61,7 +61,7 @@ func (b *BaseApi) Login(c *gin.Context) { user, msgKey, err := xpack.AuthProvider.Login(c, req, string(entrance)) if user == nil || user.MfaStatus != constant.StatusEnable { - go saveLoginLogs(c, wrapLoginErr(msgKey, err)) + go saveLoginLogs(c, req.Name, wrapLoginErr(msgKey, err)) } if msgKey == "ErrAuth" || msgKey == "ErrEntrance" { if msgKey == "ErrAuth" { @@ -108,7 +108,7 @@ func (b *BaseApi) MFALogin(c *gin.Context) { } user, msgKey, err := xpack.AuthProvider.MFALogin(c, req, string(entrance)) - go saveLoginLogs(c, wrapLoginErr(msgKey, err)) + go saveLoginLogs(c, loginLogUserName(user, req.SessionID), wrapLoginErr(msgKey, err)) if msgKey == "ErrMFA" { global.IPTracker.RecordFailure(ip) failures := initauth.GetMFASessionStore().RecordFailure(req.SessionID) @@ -163,7 +163,7 @@ func (b *BaseApi) PasskeyFinishLogin(c *gin.Context) { sessionID := c.GetHeader("Passkey-Session") entrance := loadEntranceFromRequest(c) user, msgKey, err := xpack.AuthProvider.PasskeyFinishLogin(c, sessionID, entrance) - go saveLoginLogs(c, wrapLoginErr(msgKey, err)) + go saveLoginLogs(c, loginLogUserName(user, ""), wrapLoginErr(msgKey, err)) if msgKey == "ErrAuth" || msgKey == "ErrEntrance" { if msgKey == "ErrAuth" { global.IPTracker.SetNeedCaptcha(common.GetRealClientIP(c)) @@ -500,7 +500,7 @@ func (b *BaseApi) ResetPassword(c *gin.Context) { helper.Success(c) } -func saveLoginLogs(c *gin.Context, err error) { +func saveLoginLogs(c *gin.Context, userName string, err error) { var logs model.LoginLog if err != nil { logs.Status = constant.StatusFailed @@ -509,10 +509,24 @@ func saveLoginLogs(c *gin.Context, err error) { logs.Status = constant.StatusSuccess } logs.IP = c.ClientIP() + logs.User = userName logs.Agent = c.GetHeader("User-Agent") _ = logService.CreateLoginLog(logs) } +func loginLogUserName(user *dto.UserLoginInfo, mfaSessionID string) string { + if user != nil { + return user.Name + } + if mfaSessionID == "" { + return "" + } + if session, ok := initauth.GetMFASessionStore().Get(mfaSessionID); ok { + return session.Name + } + return "" +} + func wrapLoginErr(msgKey string, err error) error { if err != nil { return err diff --git a/core/app/dto/logs.go b/core/app/dto/logs.go index 189ce6ab1..16002b7b5 100644 --- a/core/app/dto/logs.go +++ b/core/app/dto/logs.go @@ -33,13 +33,14 @@ type SearchOpLogWithPage struct { type SearchLgLogWithPage struct { PageInfo - IP string `json:"ip"` + Info string `json:"info"` Status string `json:"status"` } type LoginLog struct { ID uint `json:"id"` IP string `json:"ip"` + User string `json:"user"` Address string `json:"address"` Agent string `json:"agent"` Status string `json:"status"` diff --git a/core/app/model/logs.go b/core/app/model/logs.go index 511ebad44..f4fc71b52 100644 --- a/core/app/model/logs.go +++ b/core/app/model/logs.go @@ -25,6 +25,7 @@ type OperationLog struct { type LoginLog struct { BaseModel IP string `json:"ip"` + User string `json:"user"` Address string `json:"address"` Agent string `json:"agent"` Status string `json:"status"` diff --git a/core/app/repo/logs.go b/core/app/repo/logs.go index fbc097109..a70c7e487 100644 --- a/core/app/repo/logs.go +++ b/core/app/repo/logs.go @@ -17,7 +17,7 @@ type ILogRepo interface { CreateOperationLog(user *model.OperationLog) error PageOperationLog(limit, offset int, opts ...global.DBOption) (int64, []model.OperationLog, error) - WithByIP(ip string) global.DBOption + WithByInfo(info string) global.DBOption WithBySource(source string) global.DBOption WithByLikeOperation(operation string) global.DBOption } @@ -82,9 +82,13 @@ func (c *LogRepo) WithBySource(source string) global.DBOption { return g.Where("source = ?", source) } } -func (c *LogRepo) WithByIP(ip string) global.DBOption { +func (c *LogRepo) WithByInfo(info string) global.DBOption { return func(g *gorm.DB) *gorm.DB { - return g.Where("ip LIKE ?", "%"+ip+"%") + if len(info) == 0 { + return g + } + infoStr := "%" + info + "%" + return g.Where("ip LIKE ? OR user LIKE ?", infoStr, infoStr) } } diff --git a/core/app/service/logs.go b/core/app/service/logs.go index d43068138..0c87efc74 100644 --- a/core/app/service/logs.go +++ b/core/app/service/logs.go @@ -47,8 +47,8 @@ func (u *LogService) PageLoginLog(ctx *gin.Context, req dto.SearchLgLogWithPage) options := []global.DBOption{ repo.WithOrderDesc("created_at"), } - if len(req.IP) != 0 { - options = append(options, logRepo.WithByIP(req.IP)) + if len(req.Info) != 0 { + options = append(options, logRepo.WithByInfo(req.Info)) } if len(req.Status) != 0 { options = append(options, repo.WithByStatus(req.Status)) diff --git a/core/cmd/server/docs/docs.go b/core/cmd/server/docs/docs.go index 78ac4b6f6..e6aad283d 100644 --- a/core/cmd/server/docs/docs.go +++ b/core/cmd/server/docs/docs.go @@ -34284,7 +34284,7 @@ const docTemplate = `{ }, "dto.SearchLgLogWithPage": { "properties": { - "ip": { + "info": { "type": "string" }, "page": { diff --git a/core/cmd/server/docs/swagger.json b/core/cmd/server/docs/swagger.json index 63acdb717..6f9ea21ac 100644 --- a/core/cmd/server/docs/swagger.json +++ b/core/cmd/server/docs/swagger.json @@ -34280,7 +34280,7 @@ }, "dto.SearchLgLogWithPage": { "properties": { - "ip": { + "info": { "type": "string" }, "page": { diff --git a/core/init/migration/migrate.go b/core/init/migration/migrate.go index 7c263be8e..64009678b 100644 --- a/core/init/migration/migrate.go +++ b/core/init/migration/migrate.go @@ -47,6 +47,7 @@ func Init() { migrations.AddAIProxyMenu, migrations.AddSkillsHubMenu, migrations.AddOperationLogUser, + migrations.AddLoginLogUser, migrations.AddIsOfflineSetting, }) if err := m.Migrate(); err != nil { diff --git a/core/init/migration/migrations/init.go b/core/init/migration/migrations/init.go index 2ae703bc8..3de9a9f9d 100644 --- a/core/init/migration/migrations/init.go +++ b/core/init/migration/migrations/init.go @@ -1328,6 +1328,13 @@ var AddOperationLogUser = &gormigrate.Migration{ }, } +var AddLoginLogUser = &gormigrate.Migration{ + ID: "20260527-add-login-log-user", + Migrate: func(tx *gorm.DB) error { + return tx.AutoMigrate(&model.LoginLog{}) + }, +} + var AddIsOfflineSetting = &gormigrate.Migration{ ID: "20260429-add-is-offline-setting", Migrate: func(tx *gorm.DB) error { diff --git a/frontend/src/api/interface/log.ts b/frontend/src/api/interface/log.ts index ee907ab08..5a9b89488 100644 --- a/frontend/src/api/interface/log.ts +++ b/frontend/src/api/interface/log.ts @@ -24,11 +24,12 @@ export namespace Log { operation: string; } export interface SearchLgLog extends ReqPage { - ip: string; + info: string; status: string; } export interface LoginLogs { ip: string; + user: string; address: string; agent: string; status: string; diff --git a/frontend/src/views/log/login/index.vue b/frontend/src/views/log/login/index.vue index 23562fa29..304d1e787 100644 --- a/frontend/src/views/log/login/index.vue +++ b/frontend/src/views/log/login/index.vue @@ -16,13 +16,14 @@ - +