mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
feat: add login user display to login records (#12870)
This commit is contained in:
+18
-4
@@ -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
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -34284,7 +34284,7 @@ const docTemplate = `{
|
||||
},
|
||||
"dto.SearchLgLogWithPage": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
|
||||
@@ -34280,7 +34280,7 @@
|
||||
},
|
||||
"dto.SearchLgLogWithPage": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
|
||||
@@ -47,6 +47,7 @@ func Init() {
|
||||
migrations.AddAIProxyMenu,
|
||||
migrations.AddSkillsHubMenu,
|
||||
migrations.AddOperationLogUser,
|
||||
migrations.AddLoginLogUser,
|
||||
migrations.AddIsOfflineSetting,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
<el-option :label="$t('commons.status.success')" value="Success"></el-option>
|
||||
<el-option :label="$t('commons.status.failed')" value="Failed"></el-option>
|
||||
</el-select>
|
||||
<TableSearch @search="search()" v-model:searchName="searchIP" />
|
||||
<TableSearch @search="search()" v-model:searchName="searchInfo" />
|
||||
<TableRefresh @search="search()" />
|
||||
<TableSetting title="login-log-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="370">
|
||||
<el-table-column :label="$t('logs.loginIP')" prop="ip" />
|
||||
<el-table-column v-if="isEnterprise" :label="$t('commons.login.username')" prop="user" />
|
||||
<el-table-column :label="$t('logs.loginAddress')" prop="address" />
|
||||
<el-table-column :label="$t('logs.loginAgent')" show-overflow-tooltip prop="agent" />
|
||||
<el-table-column :label="$t('logs.loginStatus')" prop="status">
|
||||
@@ -51,6 +52,9 @@ import { cleanLogs, getLoginLogs } from '@/api/modules/log';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
|
||||
const { isEnterprise } = useGlobalStore();
|
||||
|
||||
const loading = ref();
|
||||
const data = ref();
|
||||
@@ -61,12 +65,12 @@ const paginationConfig = reactive({
|
||||
pageSize: Number(localStorage.getItem('login-log-page-size')) || 20,
|
||||
total: 0,
|
||||
});
|
||||
const searchIP = ref<string>('');
|
||||
const searchInfo = ref<string>('');
|
||||
const searchStatus = ref<string>('');
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
ip: searchIP.value,
|
||||
info: searchInfo.value,
|
||||
status: searchStatus.value,
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
|
||||
Reference in New Issue
Block a user