108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
package response
|
||
|
||
import (
|
||
"context"
|
||
"lone-services/pkg/utils"
|
||
"net/http"
|
||
"net/url"
|
||
"strconv"
|
||
|
||
"google.golang.org/grpc"
|
||
"google.golang.org/grpc/metadata"
|
||
)
|
||
|
||
type ctxKey string
|
||
|
||
const (
|
||
CtxUserId ctxKey = "X-User-Id"
|
||
CtxUserName ctxKey = "X-User-Name"
|
||
CtxRefresh ctxKey = "X-Refresh"
|
||
CtxClientIP ctxKey = "X-Client-Ip"
|
||
CtxUserAgent ctxKey = "X-User-Agent"
|
||
)
|
||
|
||
type UserInfo struct {
|
||
ID int64
|
||
Name string
|
||
RawUID string
|
||
Refresh string
|
||
ClientIP string
|
||
UserAgent string
|
||
Valid bool
|
||
}
|
||
|
||
func GetUserInfo(ctx context.Context) UserInfo {
|
||
rawUID, _ := ctx.Value(CtxUserId).(string)
|
||
name, _ := ctx.Value(CtxUserName).(string)
|
||
refresh, _ := ctx.Value(CtxRefresh).(string)
|
||
clientIP, _ := ctx.Value(CtxClientIP).(string)
|
||
userAgent, _ := ctx.Value(CtxUserAgent).(string)
|
||
|
||
info := UserInfo{
|
||
RawUID: rawUID,
|
||
Name: name,
|
||
Refresh: refresh,
|
||
ClientIP: clientIP,
|
||
UserAgent: userAgent,
|
||
}
|
||
if rawUID == "" {
|
||
return info
|
||
}
|
||
uid, err := strconv.ParseInt(rawUID, 10, 64)
|
||
if err != nil {
|
||
info.Valid = false
|
||
return info
|
||
}
|
||
info.ID = uid
|
||
info.Valid = true
|
||
return info
|
||
}
|
||
|
||
// getRealClientIP 获取真实客户端IP,优先 X‑Forwarded‑For,其次 X‑Real‑IP,最后 RemoteAddr
|
||
func getRealClientIP(r *http.Request) string {
|
||
xff := r.Header.Get("X-Forwarded-For")
|
||
if xff != "" {
|
||
return xff
|
||
}
|
||
xri := r.Header.Get("X-Real-Ip")
|
||
if xri != "" {
|
||
return xri
|
||
}
|
||
return r.RemoteAddr
|
||
}
|
||
|
||
func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||
return func(w http.ResponseWriter, r *http.Request) {
|
||
newCtx := r.Context()
|
||
newCtx = context.WithValue(newCtx, CtxUserId, r.Header.Get("X-User-Id"))
|
||
newCtx = context.WithValue(newCtx, CtxUserName, r.Header.Get("X-User-Name"))
|
||
newCtx = context.WithValue(newCtx, CtxRefresh, r.Header.Get("X-Refresh"))
|
||
newCtx = context.WithValue(newCtx, CtxClientIP, getRealClientIP(r))
|
||
newCtx = context.WithValue(newCtx, CtxUserAgent, r.UserAgent())
|
||
next(w, r.WithContext(newCtx))
|
||
}
|
||
}
|
||
|
||
func UserClientInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||
user := GetUserInfo(ctx)
|
||
md := metadata.New(map[string]string{})
|
||
|
||
if user.Valid {
|
||
md.Set("x-user-id", user.RawUID)
|
||
md.Set("x-user-name", url.QueryEscape(user.Name))
|
||
}
|
||
|
||
if user.Refresh != utils.StringEmpty {
|
||
md.Set("x-refresh", user.Refresh)
|
||
}
|
||
if user.ClientIP != utils.StringEmpty {
|
||
md.Set("x-client-ip", user.ClientIP)
|
||
}
|
||
if user.UserAgent != utils.StringEmpty {
|
||
md.Set("x-user-agent", url.QueryEscape(user.UserAgent))
|
||
}
|
||
|
||
ctx = metadata.NewOutgoingContext(ctx, md)
|
||
return invoker(ctx, method, req, reply, cc, opts...)
|
||
}
|