Merge pull request #186 from lanrenwo/act_log_device

优化审计日志的UI + 增加客户端的系统型号
This commit is contained in:
bjdgyc 2022-11-13 17:22:23 +08:00 committed by GitHub
commit 8c9e371df8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 97 additions and 74 deletions

View File

@ -41,17 +41,19 @@ type User struct {
} }
type UserActLog struct { type UserActLog struct {
Id int `json:"id" xorm:"pk autoincr not null"` Id int `json:"id" xorm:"pk autoincr not null"`
Username string `json:"username" xorm:"varchar(60)"` Username string `json:"username" xorm:"varchar(60)"`
GroupName string `json:"group_name" xorm:"varchar(60)"` GroupName string `json:"group_name" xorm:"varchar(60)"`
IpAddr string `json:"ip_addr" xorm:"varchar(32)"` IpAddr string `json:"ip_addr" xorm:"varchar(32)"`
RemoteAddr string `json:"remote_addr" xorm:"varchar(32)"` RemoteAddr string `json:"remote_addr" xorm:"varchar(32)"`
Os uint8 `json:"os" xorm:"not null default 0 Int"` Os uint8 `json:"os" xorm:"not null default 0 Int"`
Client uint8 `json:"client" xorm:"not null default 0 Int"` Client uint8 `json:"client" xorm:"not null default 0 Int"`
Version string `json:"version" xorm:"varchar(15)"` Version string `json:"version" xorm:"varchar(15)"`
Status uint8 `json:"status" xorm:"not null default 0 Int"` DeviceType string `json:"device_type" xorm:"varchar(128) not null default ''"`
Info string `json:"info" xorm:"varchar(255) not null default ''"` // 详情 PlatformVersion string `json:"platform_version" xorm:"varchar(15) not null default ''"`
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` Status uint8 `json:"status" xorm:"not null default 0 Int"`
Info string `json:"info" xorm:"varchar(255) not null default ''"` // 详情
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
} }
type IpMap struct { type IpMap struct {

View File

@ -55,7 +55,7 @@ var (
}, },
InfoOps: []string{ // 信息 InfoOps: []string{ // 信息
UserLogoutLose: "用户掉线", UserLogoutLose: "用户掉线",
UserLogoutBanner: "用户取消弹窗", UserLogoutBanner: "用户取消弹窗/客户端发起的logout",
UserLogoutClient: "用户/客户端主动断开", UserLogoutClient: "用户/客户端主动断开",
UserLogoutTimeout: "Session过期被踢下线", UserLogoutTimeout: "Session过期被踢下线",
UserLogoutAdmin: "账号被管理员踢下线", UserLogoutAdmin: "账号被管理员踢下线",
@ -121,8 +121,8 @@ func (ua *UserActLogProcess) ParseUserAgent(userAgent string) (os_idx, client_id
if len(userAgent) == 0 { if len(userAgent) == 0 {
return 5, 2, "" return 5, 2, ""
} }
// os // OS
os_idx = 2 os_idx = 5
if strings.Contains(userAgent, "windows") { if strings.Contains(userAgent, "windows") {
os_idx = 0 os_idx = 0
} else if strings.Contains(userAgent, "mac os") || strings.Contains(userAgent, "darwin_i386") { } else if strings.Contains(userAgent, "mac os") || strings.Contains(userAgent, "darwin_i386") {
@ -131,15 +131,17 @@ func (ua *UserActLogProcess) ParseUserAgent(userAgent string) (os_idx, client_id
os_idx = 4 os_idx = 4
} else if strings.Contains(userAgent, "android") { } else if strings.Contains(userAgent, "android") {
os_idx = 3 os_idx = 3
} else if strings.Contains(userAgent, "linux") {
os_idx = 2
} }
// client // Client
client_idx = 2 client_idx = 2
if strings.Contains(userAgent, "anyconnect") { if strings.Contains(userAgent, "anyconnect") {
client_idx = 0 client_idx = 0
} else if strings.Contains(userAgent, "openconnect") { } else if strings.Contains(userAgent, "openconnect") {
client_idx = 1 client_idx = 1
} }
// ver // Verion
uaSlice := strings.Split(userAgent, " ") uaSlice := strings.Split(userAgent, " ")
ver = uaSlice[len(uaSlice)-1] ver = uaSlice[len(uaSlice)-1]
if ver[0] == 'v' { if ver[0] == 'v' {

View File

@ -48,18 +48,18 @@ func TestParseUserAgent(t *testing.T) {
}, },
{ {
name: "linux", name: "linux",
args: args{userAgent: "open anyconnect vpn agent v7.08"}, args: args{userAgent: "cisco anyconnect vpn agent for linux v7.08"},
want: res{os_idx: 2, client_idx: 0, ver: "7.08"}, want: res{os_idx: 2, client_idx: 0, ver: "7.08"},
}, },
{ {
name: "openconnect", name: "openconnect",
args: args{userAgent: "openconnect-gui 1.5.3 v7.08"}, args: args{userAgent: "openconnect-gui 1.5.3 v7.08"},
want: res{os_idx: 2, client_idx: 1, ver: "7.08"}, want: res{os_idx: 5, client_idx: 1, ver: "7.08"},
}, },
{ {
name: "unknown", name: "unknown",
args: args{userAgent: "unknown 1.4.3 aabcd"}, args: args{userAgent: "unknown 1.4.3 aabcd"},
want: res{os_idx: 2, client_idx: 2, ver: ""}, want: res{os_idx: 5, client_idx: 2, ver: ""},
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -67,10 +67,12 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
} }
// 用户活动日志 // 用户活动日志
ua := dbdata.UserActLog{ ua := dbdata.UserActLog{
Username: cr.Auth.Username, Username: cr.Auth.Username,
GroupName: cr.GroupSelect, GroupName: cr.GroupSelect,
RemoteAddr: r.RemoteAddr, RemoteAddr: r.RemoteAddr,
Status: dbdata.UserAuthSuccess, Status: dbdata.UserAuthSuccess,
DeviceType: cr.DeviceId.DeviceType,
PlatformVersion: cr.DeviceId.PlatformVersion,
} }
// TODO 用户密码校验 // TODO 用户密码校验
err = dbdata.CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect) err = dbdata.CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect)
@ -100,6 +102,8 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
sess.MacAddr = strings.ToLower(cr.MacAddressList.MacAddress) sess.MacAddr = strings.ToLower(cr.MacAddressList.MacAddress)
sess.UniqueIdGlobal = cr.DeviceId.UniqueIdGlobal sess.UniqueIdGlobal = cr.DeviceId.UniqueIdGlobal
sess.UserAgent = userAgent sess.UserAgent = userAgent
sess.DeviceType = ua.DeviceType
sess.PlatformVersion = ua.PlatformVersion
sess.RemoteAddr = r.RemoteAddr sess.RemoteAddr = r.RemoteAddr
// 获取客户端mac地址 // 获取客户端mac地址
macHw, err := net.ParseMAC(sess.MacAddr) macHw, err := net.ParseMAC(sess.MacAddr)

View File

@ -196,11 +196,13 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
return return
} }
dbdata.UserActLogIns.Add(dbdata.UserActLog{ dbdata.UserActLogIns.Add(dbdata.UserActLog{
Username: sess.Username, Username: sess.Username,
GroupName: sess.Group, GroupName: sess.Group,
IpAddr: cSess.IpAddr.String(), IpAddr: cSess.IpAddr.String(),
RemoteAddr: cSess.RemoteAddr, RemoteAddr: cSess.RemoteAddr,
Status: dbdata.UserConnected, DeviceType: sess.DeviceType,
PlatformVersion: sess.PlatformVersion,
Status: dbdata.UserConnected,
}, cSess.UserAgent) }, cSess.UserAgent)
go LinkCstp(conn, bufRW, cSess) go LinkCstp(conn, bufRW, cSess)

View File

@ -64,19 +64,21 @@ type DtlsSession struct {
} }
type Session struct { type Session struct {
mux sync.RWMutex mux sync.RWMutex
Sid string // auth返回的 session-id Sid string // auth返回的 session-id
Token string // session信息的唯一token Token string // session信息的唯一token
DtlsSid string // dtls协议的 session_id DtlsSid string // dtls协议的 session_id
MacAddr string // 客户端mac地址 MacAddr string // 客户端mac地址
UniqueIdGlobal string // 客户端唯一标示 UniqueIdGlobal string // 客户端唯一标示
MacHw net.HardwareAddr MacHw net.HardwareAddr
Username string // 用户名 Username string // 用户名
Group string Group string
AuthStep string AuthStep string
AuthPass string AuthPass string
RemoteAddr string RemoteAddr string
UserAgent string UserAgent string
DeviceType string
PlatformVersion string
LastLogin time.Time LastLogin time.Time
IsActive bool IsActive bool
@ -455,11 +457,13 @@ func DelSessByStoken(stoken string) {
func AddUserActLog(cs *ConnSession) { func AddUserActLog(cs *ConnSession) {
ua := dbdata.UserActLog{ ua := dbdata.UserActLog{
Username: cs.Sess.Username, Username: cs.Sess.Username,
GroupName: cs.Sess.Group, GroupName: cs.Sess.Group,
IpAddr: cs.IpAddr.String(), IpAddr: cs.IpAddr.String(),
RemoteAddr: cs.RemoteAddr, RemoteAddr: cs.RemoteAddr,
Status: dbdata.UserLogout, DeviceType: cs.Sess.DeviceType,
PlatformVersion: cs.Sess.PlatformVersion,
Status: dbdata.UserLogout,
} }
ua.Info = dbdata.UserActLogIns.GetInfoOpsById(cs.UserLogoutCode) ua.Info = dbdata.UserActLogIns.GetInfoOpsById(cs.UserLogoutCode)
dbdata.UserActLogIns.Add(ua, cs.UserAgent) dbdata.UserActLogIns.Add(ua, cs.UserAgent)
@ -467,12 +471,14 @@ func AddUserActLog(cs *ConnSession) {
func AddUserActLogBySess(sess *Session) { func AddUserActLogBySess(sess *Session) {
ua := dbdata.UserActLog{ ua := dbdata.UserActLog{
Username: sess.Username, Username: sess.Username,
GroupName: sess.Group, GroupName: sess.Group,
IpAddr: "", IpAddr: "",
RemoteAddr: sess.RemoteAddr, RemoteAddr: sess.RemoteAddr,
Status: dbdata.UserLogout, DeviceType: sess.DeviceType,
PlatformVersion: sess.PlatformVersion,
Status: dbdata.UserLogout,
} }
ua.Info = dbdata.UserActLogIns.GetInfoOpsById(1) ua.Info = dbdata.UserActLogIns.GetInfoOpsById(dbdata.UserLogoutBanner)
dbdata.UserActLogIns.Add(ua, sess.UserAgent) dbdata.UserActLogIns.Add(ua, sess.UserAgent)
} }

View File

@ -67,12 +67,12 @@
prop="id" prop="id"
label="ID" label="ID"
sortable="custom" sortable="custom"
width="60"> width="100">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="username" prop="username"
label="用户名" label="用户名"
width="80"> width="140">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="group_name" prop="group_name"
@ -89,20 +89,35 @@
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="info"
label="操作详情"
min-width="200">
</el-table-column>
<el-table-column
prop="created_at"
label="操作时间"
width="150"
:formatter="tableDateFormat">
</el-table-column>
<el-table-column <el-table-column
prop="os" prop="os"
label="操作系统" label="操作系统"
width="82"> min-width="210">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<span v-for="(value, item, index) in osOps" :key="index"> <span v-for="(value, item, index) in osOps" :key="index">
{{ row.os == item? value: "" }} {{ row.os == item? value: "" }}
</span> </span>
<div class="sub_txt">型号:
<span v-if="row.device_type != ''">{{ row.device_type }} / {{ row.platform_version }}</span>
<span v-else> - </span>
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="client" prop="client"
label="客户端" label="客户端"
width="100"> width="150">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<span v-for="(value, item, index) in clientOps" :key="index"> <span v-for="(value, item, index) in clientOps" :key="index">
{{ row.client == item? value: "" }} {{ row.client == item? value: "" }}
@ -120,18 +135,7 @@
label="外网IP" label="外网IP"
width="120"> width="120">
</el-table-column> </el-table-column>
<el-table-column
prop="info"
label="详情">
</el-table-column>
<el-table-column
prop="created_at"
label="操作时间"
width="130"
:formatter="tableDateFormat">
</el-table-column>
</el-table> </el-table>
<div class="sh-20"></div> <div class="sh-20"></div>
<el-pagination <el-pagination
background background
@ -253,4 +257,7 @@ export default {
/deep/ .el-table td { /deep/ .el-table td {
padding: 5px 0; padding: 5px 0;
} }
.sub_txt {
color: #88909B;
}
</style> </style>

View File

@ -2,12 +2,12 @@
<div> <div>
<el-card> <el-card>
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="用户访问日志" name="access_audit">
<AuditAccess ref="auditAccess"></AuditAccess>
</el-tab-pane>
<el-tab-pane label="用户活动日志" name="act_log"> <el-tab-pane label="用户活动日志" name="act_log">
<AuditActLog ref="auditActLog"></AuditActLog> <AuditActLog ref="auditActLog"></AuditActLog>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="用户访问日志" name="access_audit">
<AuditAccess ref="auditAccess"></AuditAccess>
</el-tab-pane>
</el-tabs> </el-tabs>
</el-card> </el-card>
</div> </div>
@ -33,7 +33,7 @@ export default {
}, },
data() { data() {
return { return {
activeName: "access_audit", activeName: "act_log",
} }
}, },
methods: { methods: {