🆕新增操作日志
This commit is contained in:
parent
1cb2a919d1
commit
c1d696ac19
40
http/api/dashboard.go
Normal file
40
http/api/dashboard.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"wireguard-ui/http/param"
|
||||||
|
"wireguard-ui/http/response"
|
||||||
|
"wireguard-ui/http/vo"
|
||||||
|
"wireguard-ui/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DashboardApi struct{}
|
||||||
|
|
||||||
|
func Dashboard() DashboardApi {
|
||||||
|
return DashboardApi{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @description: 操作日志
|
||||||
|
// @receiver DashboardApi
|
||||||
|
// @param c
|
||||||
|
func (DashboardApi) List(c *gin.Context) {
|
||||||
|
var p param.Page
|
||||||
|
if err := c.ShouldBind(&p); err != nil {
|
||||||
|
response.R(c).Validator(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginUser *vo.User
|
||||||
|
if loginUser = GetCurrentLoginUser(c); c.IsAborted() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, total, err := service.Log().List(p, loginUser)
|
||||||
|
if err != nil {
|
||||||
|
response.R(c).FailedWithError(fmt.Errorf("获取操作日志失败: %v", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.R(c).Paginate(data, total, p.Current, p.Size)
|
||||||
|
}
|
108
http/middleware/request.go
Normal file
108
http/middleware/request.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"gitee.ltd/lxh/logger/log"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"wireguard-ui/http/vo"
|
||||||
|
"wireguard-ui/model"
|
||||||
|
"wireguard-ui/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// bodyWriter
|
||||||
|
// @description: 重写ResponseBody
|
||||||
|
type bodyWriter struct {
|
||||||
|
gin.ResponseWriter
|
||||||
|
body *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequestLog() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var userId string
|
||||||
|
if userInfo, ok := c.Get("user"); ok {
|
||||||
|
userId = userInfo.(*vo.User).Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始时间
|
||||||
|
start := time.Now()
|
||||||
|
host := c.Request.Host // 请求域名
|
||||||
|
path := c.Request.URL.Path // 接口地址
|
||||||
|
query := c.Request.URL.RawQuery // 参数
|
||||||
|
if strings.Contains(path, "/api/dashboard/request/list") {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var bodyStr string
|
||||||
|
if !strings.Contains(path, "/api/login") {
|
||||||
|
body, err := c.GetRawData() // body参数
|
||||||
|
if err == nil {
|
||||||
|
bodyStr = string(body)
|
||||||
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||||
|
reg := regexp.MustCompile("\\s+")
|
||||||
|
bodyStr = reg.ReplaceAllString(bodyStr, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
method := c.Request.Method // 请求方式
|
||||||
|
ip := c.ClientIP() // 取出IP
|
||||||
|
// 处理实际客户端IP
|
||||||
|
if c.Request.Header.Get("X-Real-IP") != "" {
|
||||||
|
ip = c.Request.Header.Get("X-Real-IP") // 这个是网关Nginx自定义的Header头
|
||||||
|
} else if c.Request.Header.Get("X-Forwarded-For") != "" {
|
||||||
|
ip = c.Request.Header.Get("X-Forwarded-For") // 这个是网关Nginx自定义的Header头
|
||||||
|
}
|
||||||
|
ua := c.Request.UserAgent() // UA
|
||||||
|
|
||||||
|
// 重写客户端IP
|
||||||
|
c.Request.Header.Set("X-Forwarded-For", ip)
|
||||||
|
c.Request.Header.Set("X-Real-IP", ip)
|
||||||
|
|
||||||
|
// 拦截response
|
||||||
|
bw := &bodyWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
|
||||||
|
c.Writer = bw
|
||||||
|
|
||||||
|
header := c.Request.Header
|
||||||
|
headerStr, _ := jsoniter.MarshalToString(header)
|
||||||
|
|
||||||
|
// 执行下一步请求
|
||||||
|
c.Next()
|
||||||
|
// 计算耗时
|
||||||
|
cost := time.Since(start).Milliseconds()
|
||||||
|
|
||||||
|
// 组装实体
|
||||||
|
l := model.RequestLog{
|
||||||
|
UserId: userId,
|
||||||
|
ClientIP: ip,
|
||||||
|
Host: host,
|
||||||
|
Method: method,
|
||||||
|
Uri: path,
|
||||||
|
Header: headerStr,
|
||||||
|
Body: bodyStr,
|
||||||
|
Form: "",
|
||||||
|
Query: query,
|
||||||
|
UserAgent: ua,
|
||||||
|
Cost: cost,
|
||||||
|
StatusCode: c.Writer.Status(),
|
||||||
|
Response: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是返回200,把返回值保存一下
|
||||||
|
if c.Writer.Status() != 200 {
|
||||||
|
resp := bw.body.String()
|
||||||
|
l.Response = resp
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if er := service.Log().CreateLog(l); er != nil {
|
||||||
|
log.Debugf("请求日志: %+v", l)
|
||||||
|
log.Errorf("保存请求日志失败: %v", er)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ import (
|
|||||||
// @description: 登陆相关API
|
// @description: 登陆相关API
|
||||||
// @param r
|
// @param r
|
||||||
func ClientApi(r *gin.RouterGroup) {
|
func ClientApi(r *gin.RouterGroup) {
|
||||||
client := r.Group("client", middleware.Authorization())
|
client := r.Group("client", middleware.Authorization(), middleware.RequestLog())
|
||||||
{
|
{
|
||||||
client.POST("", api.Client().Save) // 新增/编辑客户端
|
client.POST("", api.Client().Save) // 新增/编辑客户端
|
||||||
client.DELETE("/:id", api.Client().Delete) // 删除客户端
|
client.DELETE("/:id", api.Client().Delete) // 删除客户端
|
||||||
|
17
http/router/dashboard.go
Normal file
17
http/router/dashboard.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"wireguard-ui/http/api"
|
||||||
|
"wireguard-ui/http/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DashboardApi
|
||||||
|
// @description: 控制台相关接口
|
||||||
|
// @param r
|
||||||
|
func DashboardApi(r *gin.RouterGroup) {
|
||||||
|
dashboard := r.Group("dashboard", middleware.Authorization(), middleware.RequestLog())
|
||||||
|
{
|
||||||
|
dashboard.GET("/request/list", api.Dashboard().List) // 请求日志
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,14 @@ package router
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"wireguard-ui/http/api"
|
"wireguard-ui/http/api"
|
||||||
|
"wireguard-ui/http/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoginApi
|
// LoginApi
|
||||||
// @description: 登陆相关API
|
// @description: 登陆相关API
|
||||||
// @param r
|
// @param r
|
||||||
func LoginApi(r *gin.RouterGroup) {
|
func LoginApi(r *gin.RouterGroup) {
|
||||||
login := r.Group("/login")
|
login := r.Group("/login", middleware.RequestLog())
|
||||||
{
|
{
|
||||||
login.GET("/captcha", api.Login().Captcha) // 获取登陆验证码
|
login.GET("/captcha", api.Login().Captcha) // 获取登陆验证码
|
||||||
login.POST("", api.Login().Login) // 登陆
|
login.POST("", api.Login().Login) // 登陆
|
||||||
|
@ -47,5 +47,6 @@ func Rooters() {
|
|||||||
UserApi,
|
UserApi,
|
||||||
ClientApi,
|
ClientApi,
|
||||||
SettingApi,
|
SettingApi,
|
||||||
|
DashboardApi,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,14 @@ package router
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"wireguard-ui/http/api"
|
"wireguard-ui/http/api"
|
||||||
|
"wireguard-ui/http/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SettingApi
|
// SettingApi
|
||||||
// @description: 设置相关API
|
// @description: 设置相关API
|
||||||
// @param r
|
// @param r
|
||||||
func SettingApi(r *gin.RouterGroup) {
|
func SettingApi(r *gin.RouterGroup) {
|
||||||
setting := r.Group("setting")
|
setting := r.Group("setting", middleware.Authorization(), middleware.RequestLog())
|
||||||
{
|
{
|
||||||
setting.POST("", api.Setting().Set) // 新增/编辑设置
|
setting.POST("", api.Setting().Set) // 新增/编辑设置
|
||||||
setting.DELETE("/:code", api.Setting().Delete) // 删除配置
|
setting.DELETE("/:code", api.Setting().Delete) // 删除配置
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
// @description: 用户相关API
|
// @description: 用户相关API
|
||||||
// @param r
|
// @param r
|
||||||
func UserApi(r *gin.RouterGroup) {
|
func UserApi(r *gin.RouterGroup) {
|
||||||
userApi := r.Group("user", middleware.Authorization())
|
userApi := r.Group("user", middleware.Authorization(), middleware.RequestLog())
|
||||||
{
|
{
|
||||||
userApi.GET("/info", api.User().GetLoginUser) // 获取当前登陆用户信息
|
userApi.GET("/info", api.User().GetLoginUser) // 获取当前登陆用户信息
|
||||||
userApi.POST("", api.User().SaveUser) // 新增/编辑用户
|
userApi.POST("", api.User().SaveUser) // 新增/编辑用户
|
||||||
|
14
http/vo/log.go
Normal file
14
http/vo/log.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package vo
|
||||||
|
|
||||||
|
import "wireguard-ui/model"
|
||||||
|
|
||||||
|
type SystemLogItem struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
ClientIP string `json:"clientIP"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Uri string `json:"uri"`
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
CreatedAt model.JsonTime `json:"createdAt"`
|
||||||
|
}
|
@ -16,3 +16,7 @@ type RequestLog struct {
|
|||||||
StatusCode int `json:"statusCode" gorm:"type:int(10);comment:'响应状态码'"`
|
StatusCode int `json:"statusCode" gorm:"type:int(10);comment:'响应状态码'"`
|
||||||
Response string `json:"response" gorm:"type:text;comment:'返回数据'"`
|
Response string `json:"response" gorm:"type:text;comment:'返回数据'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (RequestLog) TableName() string {
|
||||||
|
return "t_request_log"
|
||||||
|
}
|
||||||
|
49
service/log.go
Normal file
49
service/log.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
gdb "wireguard-ui/global/client"
|
||||||
|
"wireguard-ui/global/constant"
|
||||||
|
"wireguard-ui/http/param"
|
||||||
|
"wireguard-ui/http/vo"
|
||||||
|
"wireguard-ui/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type log struct {
|
||||||
|
*gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func Log() log {
|
||||||
|
return log{
|
||||||
|
gdb.DB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateLog
|
||||||
|
// @description: 创建日志
|
||||||
|
// @receiver l
|
||||||
|
// @param log
|
||||||
|
// @return error
|
||||||
|
func (l log) CreateLog(log model.RequestLog) error {
|
||||||
|
return l.Create(&log).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @description: 分页列表
|
||||||
|
// @receiver s
|
||||||
|
// @param p
|
||||||
|
// @return data
|
||||||
|
// @return total
|
||||||
|
// @return err
|
||||||
|
func (l log) List(p param.Page, loginUser *vo.User) (data []vo.SystemLogItem, total int64, err error) {
|
||||||
|
sel := l.Scopes(Paginate(p.Current, p.Size)).Table("t_request_log as tsl").
|
||||||
|
Joins("LEFT JOIN t_user as tu ON tu.id = tsl.user_id").
|
||||||
|
Select("tsl.id", "tu.nickname as username", "tsl.client_ip", "tsl.method", "tsl.status_code", "tsl.host", "tsl.uri", "tsl.created_at").
|
||||||
|
Order("tsl.created_at DESC")
|
||||||
|
|
||||||
|
if loginUser.IsAdmin == constant.NormalAdmin {
|
||||||
|
sel.Where("tsl.user_id = ?", loginUser.Id)
|
||||||
|
}
|
||||||
|
err = sel.Find(&data).Offset(-1).Limit(-1).Count(&total).Error
|
||||||
|
return
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user