Files
lone-services/bff/internal/request/user.go
T
zzw 32226e2fa9
CI / changes (push) Successful in 1m31s
CI / ad (push) Successful in 1s
CI / admin (push) Successful in 0s
CI / analysis (push) Successful in 0s
CI / bff (push) Successful in 27s
CI / chore (push) Successful in 1s
CI / equipment (push) Successful in 0s
CI / express (push) Successful in 0s
CI / factory (push) Successful in 1s
CI / message (push) Successful in 0s
CI / order (push) Successful in 0s
CI / payment (push) Successful in 0s
CI / percutaneous (push) Successful in 0s
CI / product (push) Successful in 1s
CI / record (push) Successful in 0s
CI / sale (push) Successful in 0s
CI / store (push) Successful in 0s
CI / support (push) Successful in 0s
CI / user (push) Successful in 0s
CI / task (push) Successful in 1s
CI / wecom (push) Successful in 0s
CI / water (push) Successful in 1s
CI / ws (push) Successful in 0s
chore: faceback white list
2026-10-27 14:52:05 +08:00

283 lines
9.3 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"
CtxBizId ctxKey = "X-Biz-Id"
CtxRawBody ctxKey = "X-Raw-Body"
CtxOssAuth ctxKey = "X-Oss-Authorization"
CtxOssPubKeyURL ctxKey = "X-Oss-Pub-Key-Url"
CtxRequestPath ctxKey = "X-Request-Path"
CtxRequestQuery ctxKey = "X-Request-Query"
)
var callbackPrefixes = []string{
"/api/v3/express/",
"/api/v2/analysis/oss/callback",
"/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
BizId string
RawBody string
OssAuth string
OssPubKeyURL string
RequestPath string
RequestQuery 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)
bizId, _ := ctx.Value(CtxBizId).(string)
rawBody, _ := ctx.Value(CtxRawBody).(string)
ossAuth, _ := ctx.Value(CtxOssAuth).(string)
ossPubKeyURL, _ := ctx.Value(CtxOssPubKeyURL).(string)
requestPath, _ := ctx.Value(CtxRequestPath).(string)
requestQuery, _ := ctx.Value(CtxRequestQuery).(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,
BizId: bizId,
RawBody: rawBody,
OssAuth: ossAuth,
OssPubKeyURL: ossPubKeyURL,
RequestPath: requestPath,
RequestQuery: requestQuery,
}
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"))
newCtx = context.WithValue(newCtx, CtxBizId, r.Header.Get("X-Biz-Id"))
if isCallbackPath(r.URL.Path) {
newCtx = context.WithValue(newCtx, CtxOssAuth, r.Header.Get("Authorization"))
newCtx = context.WithValue(newCtx, CtxOssPubKeyURL, r.Header.Get("X-Oss-Pub-Key-Url"))
newCtx = context.WithValue(newCtx, CtxRequestPath, r.URL.Path)
newCtx = context.WithValue(newCtx, CtxRequestQuery, r.URL.RawQuery)
}
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))
}
setMDIfNotEmpty(md, "x-biz-id", user.BizId)
setMDIfNotEmpty(md, "x-oss-authorization", user.OssAuth)
setMDIfNotEmpty(md, "x-oss-pub-key-url", user.OssPubKeyURL)
setMDIfNotEmpty(md, "x-request-path", user.RequestPath)
setMDIfNotEmpty(md, "x-request-query", user.RequestQuery)
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))
}
setMDIfNotEmpty(md, "x-biz-id", user.BizId)
setMDIfNotEmpty(md, "x-oss-authorization", user.OssAuth)
setMDIfNotEmpty(md, "x-oss-pub-key-url", user.OssPubKeyURL)
setMDIfNotEmpty(md, "x-request-path", user.RequestPath)
setMDIfNotEmpty(md, "x-request-query", user.RequestQuery)
newCtx := metadata.NewOutgoingContext(ctx, md)
return streamer(newCtx, desc, cc, method, opts...)
}