Files
lone-services/bff/internal/request/user.go
T
gjs 6b8500ac5e
CI / changes (push) Successful in 1m29s
CI / ad (push) Successful in 0s
CI / admin (push) Successful in 0s
CI / bff (push) Successful in 29s
CI / chore (push) Successful in 0s
CI / equipment (push) Successful in 0s
CI / express (push) Successful in 0s
CI / factory (push) Successful in 0s
CI / message (push) Successful in 1s
CI / order (push) Successful in 0s
CI / payment (push) Successful in 0s
CI / product (push) Successful in 1s
CI / record (push) Successful in 0s
CI / sale (push) Successful in 20s
CI / support (push) Successful in 1s
CI / task (push) Successful in 0s
CI / user (push) Successful in 0s
CI / wecom (push) Successful in 1s
ws
2026-10-08 14:14:39 +08:00

245 lines
7.6 KiB
Go

package request
import (
"bytes"
"context"
"encoding/base64"
"io"
"lone-services/pkg/utils"
"net/http"
"net/url"
"strconv"
"strings"
"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"
CtxClientCode ctxKey = "X-Client-Code"
CtxSaleId ctxKey = "X-Sale-Id"
CtxSaleName ctxKey = "X-Sale-Name"
CtxSaleMobile ctxKey = "X-Sale-Mobile"
CtxSaleProvince ctxKey = "X-Sale-Province"
CtxStoreId ctxKey = "X-Store-Id"
CtxStoreName ctxKey = "X-Store-Name"
CtxGroupId ctxKey = "X-Group-Id"
CtxGroupName ctxKey = "X-Group-Name"
CtxUserType ctxKey = "X-User-Type"
CtxRawBody ctxKey = "X-Raw-Body"
)
var callbackPrefixes = []string{
"/api/v3/express/",
"/api/v3/other1/",
"/api/v3/other2/",
}
type UserInfo struct {
ID int64
Name string
RawUID string
Refresh string
ClientIP string
UserAgent string
Type string
ClientCode string
SaleId string
SaleName string
SaleMobile string
SaleProvince string
StoreId string
StoreName string
GroupId string
GroupName string
RawBody 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)
userType, _ := ctx.Value(CtxUserType).(string)
clientCode, _ := ctx.Value(CtxClientCode).(string)
saleId, _ := ctx.Value(CtxSaleId).(string)
saleName, _ := ctx.Value(CtxSaleName).(string)
saleMobile, _ := ctx.Value(CtxSaleMobile).(string)
saleProvince, _ := ctx.Value(CtxSaleProvince).(string)
storeId, _ := ctx.Value(CtxStoreId).(string)
storeName, _ := ctx.Value(CtxStoreName).(string)
groupId, _ := ctx.Value(CtxGroupId).(string)
groupName, _ := ctx.Value(CtxGroupName).(string)
rawBody, _ := ctx.Value(CtxRawBody).(string)
info := UserInfo{
RawUID: rawUID,
Name: name,
Refresh: refresh,
ClientIP: clientIP,
UserAgent: userAgent,
Type: userType,
ClientCode: clientCode,
SaleId: saleId,
SaleName: saleName,
SaleMobile: saleMobile,
SaleProvince: saleProvince,
StoreId: storeId,
StoreName: storeName,
GroupId: groupId,
GroupName: groupName,
RawBody: rawBody,
}
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
}
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
}
// UserReadMiddleware
/** 增加透传的方法
* 1、这里加上代码
* 2、UserClientInterceptor这个方法里也要写相应的代码对可以
*/
func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
newCtx := r.Context()
body, _ := io.ReadAll(r.Body)
r.Body = io.NopCloser(bytes.NewBuffer(body))
newCtx = context.WithValue(newCtx, CtxRawBody, base64.StdEncoding.EncodeToString(body))
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())
newCtx = context.WithValue(newCtx, CtxUserType, r.Header.Get("X-User-Type"))
newCtx = context.WithValue(newCtx, CtxClientCode, r.Header.Get("X-Client-Code"))
newCtx = context.WithValue(newCtx, CtxSaleId, r.Header.Get("X-Sale-Id"))
newCtx = context.WithValue(newCtx, CtxSaleName, r.Header.Get("X-Sale-Name"))
newCtx = context.WithValue(newCtx, CtxSaleMobile, r.Header.Get("X-Sale-Mobile"))
newCtx = context.WithValue(newCtx, CtxSaleProvince, r.Header.Get("X-Sale-Province"))
newCtx = context.WithValue(newCtx, CtxStoreId, r.Header.Get("X-Store-Id"))
newCtx = context.WithValue(newCtx, CtxStoreName, r.Header.Get("X-Store-Name"))
newCtx = context.WithValue(newCtx, CtxGroupId, r.Header.Get("X-Group-Id"))
newCtx = context.WithValue(newCtx, CtxGroupName, r.Header.Get("X-Group-Name"))
next(w, r.WithContext(newCtx))
}
}
func isCallbackPath(path string) bool {
for _, prefix := range callbackPrefixes {
if strings.HasPrefix(path, prefix) {
return true
}
}
return false
}
func setMDIfNotEmpty(md metadata.MD, key, value string) {
if value != utils.StringEmpty {
md.Set(key, value)
}
}
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))
}
setMDIfNotEmpty(md, "x-raw-body", user.RawBody)
setMDIfNotEmpty(md, "x-refresh", user.Refresh)
setMDIfNotEmpty(md, "x-client-ip", user.ClientIP)
if user.UserAgent != utils.StringEmpty {
md.Set("x-user-agent", url.QueryEscape(user.UserAgent))
}
setMDIfNotEmpty(md, "x-user-type", user.Type)
setMDIfNotEmpty(md, "x-client-code", user.ClientCode)
setMDIfNotEmpty(md, "x-sale-id", user.SaleId)
if user.SaleName != utils.StringEmpty {
md.Set("x-sale-name", url.QueryEscape(user.SaleName))
}
setMDIfNotEmpty(md, "x-sale-mobile", user.SaleMobile)
setMDIfNotEmpty(md, "x-sale-province", user.SaleProvince)
setMDIfNotEmpty(md, "x-store-id", user.StoreId)
if user.StoreName != utils.StringEmpty {
md.Set("x-store-name", url.QueryEscape(user.StoreName))
}
setMDIfNotEmpty(md, "x-group-id", user.GroupId)
if user.GroupName != utils.StringEmpty {
md.Set("x-group-name", url.QueryEscape(user.GroupName))
}
ctx = metadata.NewOutgoingContext(ctx, md)
return invoker(ctx, method, req, reply, cc, opts...)
}
// UserStreamInterceptor gRPC Stream客户端拦截器,用于ws桥接的双向流透传metadata
func UserStreamInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, 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))
}
setMDIfNotEmpty(md, "x-raw-body", user.RawBody)
setMDIfNotEmpty(md, "x-refresh", user.Refresh)
setMDIfNotEmpty(md, "x-client-ip", user.ClientIP)
if user.UserAgent != utils.StringEmpty {
md.Set("x-user-agent", url.QueryEscape(user.UserAgent))
}
setMDIfNotEmpty(md, "x-user-type", user.Type)
setMDIfNotEmpty(md, "x-client-code", user.ClientCode)
setMDIfNotEmpty(md, "x-sale-id", user.SaleId)
if user.SaleName != utils.StringEmpty {
md.Set("x-sale-name", url.QueryEscape(user.SaleName))
}
setMDIfNotEmpty(md, "x-sale-mobile", user.SaleMobile)
setMDIfNotEmpty(md, "x-sale-province", user.SaleProvince)
setMDIfNotEmpty(md, "x-store-id", user.StoreId)
if user.StoreName != utils.StringEmpty {
md.Set("x-store-name", url.QueryEscape(user.StoreName))
}
setMDIfNotEmpty(md, "x-group-id", user.GroupId)
if user.GroupName != utils.StringEmpty {
md.Set("x-group-name", url.QueryEscape(user.GroupName))
}
newCtx := metadata.NewOutgoingContext(ctx, md)
return streamer(newCtx, desc, cc, method, opts...)
}