zero-admin-2

思考并回答以下问题:

middleware

api/internal/middleware/checkurlmiddleware.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package middleware

import (
"encoding/json"
"fmt"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest/httpx"
"net/http"
"strings"
"zero-admin/api/internal/common/errorx"
)

type CheckUrlMiddleware struct {
Redis *redis.Redis
}

func NewCheckUrlMiddleware(Redis *redis.Redis) *CheckUrlMiddleware {
return &CheckUrlMiddleware{Redis: Redis}
}

func (m *CheckUrlMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {

//判断请求header中是否携带了x-user-id
userId := r.Context().Value("userId").(json.Number).String()
userName := r.Context().Value("userName").(string)
if userId == "" || userName == "" {
logx.WithContext(r.Context()).Errorf("缺少必要参数x-user-id")
httpx.Error(w, errorx.NewDefaultError("缺少必要参数x-user-id"))
return
}

if r.RequestURI == "/api/sys/user/currentUser" || r.RequestURI == "/api/sys/user/selectAllData" || r.RequestURI == "/api/sys/role/queryMenuByRoleId" {
next(w, r)
return
}
//获取用户能访问的url
urls, err := m.Redis.Get(userId)
if err != nil {
logx.WithContext(r.Context()).Errorf("用户:%s,获取redis连接异常", userName)
httpx.Error(w, errorx.NewDefaultError(fmt.Sprintf("用户:%s,获取redis连接异常", userName)))
return
}

if len(strings.TrimSpace(urls)) == 0 {
logx.WithContext(r.Context()).Errorf("用户: %s,还没有登录", userName)
httpx.Error(w, errorx.NewDefaultError(fmt.Sprintf("用户: %s,还没有登录,请先登录", userName)))
return
}

backUrls := strings.Split(urls, ",")

b := false
for _, url := range backUrls {
if url == r.RequestURI {
b = true
break
}
}

if !b {
logx.WithContext(r.Context()).Errorf("用户: %s,没有访问: %s路径的权限", userName, r.RequestURI)
httpx.Error(w, errorx.NewDefaultError(fmt.Sprintf("用户: %s,没有访问: %s,路径的的权限,请联系管理员", userName, r.RequestURI)))
return
}

next(w, r)
}
}

api/internal/middleware/addloglmiddleware.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package middleware

import (
"bytes"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"io/ioutil"
"net/http"
"time"
"zero-admin/rpc/sys/client/syslogservice"
"zero-admin/rpc/sys/sysclient"
)

type AddLogMiddleware struct {
Sys syslogservice.SysLogService
}

func NewAddLogMiddleware(Sys syslogservice.SysLogService) *AddLogMiddleware {
return &AddLogMiddleware{Sys: Sys}
}

// Handle 参考chatgpt实现
func (m *AddLogMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {

uri := r.RequestURI
if uri == "/api/sys/user/login" || uri == "/api/sys/upload" {
logx.WithContext(r.Context()).Infof("Request: %s %s", r.Method, uri)
next(w, r)
return
}

userName := r.Context().Value("userName").(string)

startTime := time.Now()

// 读取请求主体
body, err := ioutil.ReadAll(r.Body)
if err != nil {
logx.WithContext(r.Context()).Errorf("Failed to read request body: %v", err)
}

// 创建一个新的请求主体用于后续读取
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))

// 打印请求参数日志
logx.WithContext(r.Context()).Infof("Request: %s %s %s", r.Method, uri, body)

// 创建一个自定义的 ResponseWriter,用于记录响应
recorder := &responseRecorder{
ResponseWriter: w,
statusCode: http.StatusOK,
body: make([]byte, 0),
}

// 调用下一个处理器,捕获响应
next(recorder, r)

// 打印响应日志
responseBoy := string(recorder.body)
// 响应参数较多,可以不打印
//logx.WithContext(r.Context()).Infof("Response: %s %s %s", r.Method, r.RequestURI, responseBoy)

// 打印请求和响应耗时
duration := time.Since(startTime)
// 添加操作日志
_, _ = m.Sys.SysLogAdd(r.Context(), &sysclient.SysLogAddReq{
UserName: userName,
Operation: r.Method,
Method: uri,
RequestParams: string(body),
Time: duration.Milliseconds(),
Ip: httpx.GetRemoteAddr(r),
ResponseParams: responseBoy,
})
}
}

// 自定义的 ResponseWriter
type responseRecorder struct {
http.ResponseWriter
statusCode int
body []byte
}

// WriteHeader 重写 WriteHeader 方法,捕获状态码
func (r *responseRecorder) WriteHeader(statusCode int) {
r.statusCode = statusCode
r.ResponseWriter.WriteHeader(statusCode)
}

// 重写 Write 方法,捕获响应数据
func (r *responseRecorder) Write(body []byte) (int, error) {
r.body = body
return r.ResponseWriter.Write(body)
}

0%