调整 rsa 密钥解析函数

This commit is contained in:
2025-06-16 10:19:38 +08:00
parent 4c491f5c2e
commit 2903be6223
19 changed files with 235 additions and 96 deletions

View File

@ -19,4 +19,5 @@ type IRewardV1 interface {
UpdateStoreReward(ctx context.Context, req *v1.UpdateStoreRewardReq) (res *v1.UpdateStoreRewardRes, err error) UpdateStoreReward(ctx context.Context, req *v1.UpdateStoreRewardReq) (res *v1.UpdateStoreRewardRes, err error)
DeleteSystemReward(ctx context.Context, req *v1.DeleteSystemRewardReq) (res *v1.DeleteSystemRewardRes, err error) DeleteSystemReward(ctx context.Context, req *v1.DeleteSystemRewardReq) (res *v1.DeleteSystemRewardRes, err error)
DeleteStoreReward(ctx context.Context, req *v1.DeleteStoreRewardReq) (res *v1.DeleteStoreRewardRes, err error) DeleteStoreReward(ctx context.Context, req *v1.DeleteStoreRewardReq) (res *v1.DeleteStoreRewardRes, err error)
RewardCallback(ctx context.Context, req *v1.RewardCallbackReq) (res *v1.RewardCallbackRes, err error)
} }

View File

@ -131,3 +131,26 @@ type DeleteStoreRewardReq struct {
type DeleteStoreRewardRes struct { type DeleteStoreRewardRes struct {
Success bool `json:"success" dc:"删除成功"` Success bool `json:"success" dc:"删除成功"`
} }
type RewardCallbackReq struct {
g.Meta `path:"/reward/callback" method:"post" tags:"Reward" summary:"(系统)奖励回调"`
UId string `json:"uid"`
OrderId string `json:"order_id"`
PrizeChannelId string `json:"prize_channel_id"`
PrizeId string `json:"prize_id" v:"required|#券ID不能为空"`
PrizeType uint32 `json:"prize_type"`
PrizeSubType uint32 `json:"prize_sub_type"`
Num uint32 `json:"num"`
CustomInfo string `json:"custom_info"`
}
type RewardCallbackRes struct {
ErrCode int32 `json:"errcode"` // 必填
ErrMsg string `json:"errmsg"`
Appid string `json:"appid"`
OrderId string `json:"order_id"` // 必填
Data []RewardCallbackData `json:"data"` // 必填
}
type RewardCallbackData struct {
PrizeCode string `json:"prize_code"` // 必填
Comment string `json:"comment"`
}

View File

@ -0,0 +1,29 @@
package reward
import (
"context"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/api/reward/v1"
)
func (c *ControllerV1) RewardCallback(ctx context.Context, req *v1.RewardCallbackReq) (res *v1.RewardCallbackRes, err error) {
appId := g.RequestFromCtx(ctx).GetHeader("Custom-Data-Appid")
timestamp := g.RequestFromCtx(ctx).GetHeader("Custom-Data-Timestamp")
nonce := g.RequestFromCtx(ctx).GetHeader("Custom-Data-Nonce")
auth := g.RequestFromCtx(ctx).GetHeader("Custom-Data-Auth")
glog.Infof(ctx, "appId: %s, timestamp: %s, nonce: %s, auth: %s", appId, timestamp, nonce, auth)
secret := ""
data := fmt.Sprintf("%s%s%s%s%d%d%d%s%s%s#%s", req.UId, req.OrderId, req.PrizeId, req.PrizeChannelId, req.PrizeType, req.PrizeSubType, req.Num, appId, timestamp, nonce, secret)
if data != auth {
}
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}

View File

@ -2,6 +2,7 @@ package storeAdmin
import ( import (
"context" "context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@ -10,5 +11,6 @@ import (
) )
func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error) { func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error) {
g.RequestFromCtx(ctx)
return nil, gerror.NewCode(gcode.CodeNotImplemented) return nil, gerror.NewCode(gcode.CodeNotImplemented)
} }

View File

@ -34,6 +34,7 @@ type RewardsColumns struct {
CreatedAt string // 创建时间 CreatedAt string // 创建时间
UpdatedAt string // 更新时间 UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳 DeletedAt string // 软删除时间戳
RemainStock string // 剩余库存数量
} }
// rewardsColumns holds the columns for the table rewards. // rewardsColumns holds the columns for the table rewards.
@ -51,6 +52,7 @@ var rewardsColumns = RewardsColumns{
CreatedAt: "created_at", CreatedAt: "created_at",
UpdatedAt: "updated_at", UpdatedAt: "updated_at",
DeletedAt: "deleted_at", DeletedAt: "deleted_at",
RemainStock: "remain_stock",
} }
// NewRewardsDao creates and returns a new DAO object for table data access. // NewRewardsDao creates and returns a new DAO object for table data access.

View File

@ -27,7 +27,6 @@ type UsersColumns struct {
Nickname string // 昵称 Nickname string // 昵称
Avatar string // 用户头像URL Avatar string // 用户头像URL
PasswordHash string // 密码哈希 PasswordHash string // 密码哈希
Email string // 邮箱地址
PhoneNumber string // 手机号 PhoneNumber string // 手机号
WxPopenId string // 微信 PopenID WxPopenId string // 微信 PopenID
QqPopenId string // QQ PopenID QqPopenId string // QQ PopenID
@ -48,7 +47,6 @@ var usersColumns = UsersColumns{
Nickname: "nickname", Nickname: "nickname",
Avatar: "avatar", Avatar: "avatar",
PasswordHash: "password_hash", PasswordHash: "password_hash",
Email: "email",
PhoneNumber: "phone_number", PhoneNumber: "phone_number",
WxPopenId: "wx_popen_id", WxPopenId: "wx_popen_id",
QqPopenId: "qq_popen_id", QqPopenId: "qq_popen_id",

View File

@ -13,7 +13,6 @@ import (
_ "server/internal/logic/reward" _ "server/internal/logic/reward"
_ "server/internal/logic/rewardType" _ "server/internal/logic/rewardType"
_ "server/internal/logic/role" _ "server/internal/logic/role"
_ "server/internal/logic/sms"
_ "server/internal/logic/store" _ "server/internal/logic/store"
_ "server/internal/logic/storeAdmin" _ "server/internal/logic/storeAdmin"
_ "server/internal/logic/storeRole" _ "server/internal/logic/storeRole"

View File

@ -156,7 +156,6 @@ func (s *sUser) Info(ctx context.Context, in *model.UserInfoIn) (out *model.User
Username: user.Username, Username: user.Username,
Nickname: user.Nickname, Nickname: user.Nickname,
Avatar: user.Avatar, Avatar: user.Avatar,
Email: user.Email,
PhoneNumber: user.PhoneNumber, PhoneNumber: user.PhoneNumber,
WxPopenId: user.WxPopenId, WxPopenId: user.WxPopenId,
QQPopenId: user.QqPopenId, QQPopenId: user.QqPopenId,

View File

@ -25,4 +25,5 @@ type Rewards struct {
CreatedAt *gtime.Time // 创建时间 CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间 UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳 DeletedAt *gtime.Time // 软删除时间戳
RemainStock interface{} // 剩余库存数量
} }

View File

@ -18,7 +18,6 @@ type Users struct {
Nickname interface{} // 昵称 Nickname interface{} // 昵称
Avatar interface{} // 用户头像URL Avatar interface{} // 用户头像URL
PasswordHash interface{} // 密码哈希 PasswordHash interface{} // 密码哈希
Email interface{} // 邮箱地址
PhoneNumber interface{} // 手机号 PhoneNumber interface{} // 手机号
WxPopenId interface{} // 微信 PopenID WxPopenId interface{} // 微信 PopenID
QqPopenId interface{} // QQ PopenID QqPopenId interface{} // QQ PopenID

View File

@ -23,4 +23,5 @@ type Rewards struct {
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
RemainStock int `json:"remainStock" orm:"remain_stock" description:"剩余库存数量"` // 剩余库存数量
} }

View File

@ -16,7 +16,6 @@ type Users struct {
Nickname string `json:"nickname" orm:"nickname" description:"昵称"` // 昵称 Nickname string `json:"nickname" orm:"nickname" description:"昵称"` // 昵称
Avatar string `json:"avatar" orm:"avatar" description:"用户头像URL"` // 用户头像URL Avatar string `json:"avatar" orm:"avatar" description:"用户头像URL"` // 用户头像URL
PasswordHash string `json:"passwordHash" orm:"password_hash" description:"密码哈希"` // 密码哈希 PasswordHash string `json:"passwordHash" orm:"password_hash" description:"密码哈希"` // 密码哈希
Email string `json:"email" orm:"email" description:"邮箱地址"` // 邮箱地址
PhoneNumber string `json:"phoneNumber" orm:"phone_number" description:"手机号"` // 手机号 PhoneNumber string `json:"phoneNumber" orm:"phone_number" description:"手机号"` // 手机号
WxPopenId string `json:"wxPopenId" orm:"wx_popen_id" description:"微信 PopenID"` // 微信 PopenID WxPopenId string `json:"wxPopenId" orm:"wx_popen_id" description:"微信 PopenID"` // 微信 PopenID
QqPopenId string `json:"qqPopenId" orm:"qq_popen_id" description:"QQ PopenID"` // QQ PopenID QqPopenId string `json:"qqPopenId" orm:"qq_popen_id" description:"QQ PopenID"` // QQ PopenID

View File

@ -34,10 +34,6 @@ wechat:
ticketExpire: 60 ticketExpire: 60
token: "arenax" token: "arenax"
rsa:
publickey: "./manifest/config/public.pem"
privatekey: "./manifest/config/private.pem"
#OSS配置 #OSS配置
oss: oss:
aliyun: aliyun:
@ -47,5 +43,7 @@ oss:
endpoint: "oss-us-east-1.aliyuncs.com" endpoint: "oss-us-east-1.aliyuncs.com"
gamelife: gamelife:
platId: "b1749611654" platId: "quanyou"
secret: "LqPQ2gbF"
mode: "test" mode: "test"
rsaKey: "./manifest/config/全游-测试环境密钥.txt"

View File

@ -1,28 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHXJazSOFka3q+
xyBqVuLtK+OElsgRQyQCRakBvcBkq5lIl1G+6ivuju+q3bemiYzOWah/H/+7848c
yu505CpJtRUvPiSaXqhwIAWAHvD1ckLo9xw3eh9uYdmnZx92+d+oKVcjZWz/M6qQ
g6GYf8kE0x8zDKw1Xd89y6xzo7DqFNnE9BHSxeFNSAgp+MOBPn7X2mdDOWl6eGLs
qXK6BTTFyeS0JaH1t0ra6JyQ5wau3WKpB22G3pK9+u8MQPKjM+JXdIZFA0eT2SeI
qbB0xRfU4fOmhn/eXVyNYws1s92hPq1Lu8/QHf6m6QNbmualgaSiEo/ogKGN1urj
/ARsTdbpAgMBAAECggEAF2DnakmhHA3wIjkUISmmgd39qq28GjclZfsQCIv0Sa7V
h5MS/E1HjylCvZkTmgDRv+X+Uw58xcJ4KjnmW2v43cgXw5QREFRe9RaivJEbftjg
M4pSZkaCXTcrN115MrxPY6TYNvXSkHUk9Va2tzcCygGItvFuYL04zFx8CXDxIkx7
4NP3F3AGbQ4GACoIUsKNuQ0WIZO6WrxJP0sGH1iz+oxDIlEkEZAYHAKIIna3gaY5
YBvOmRScGDO2K05fLxDJUK0x4nxkBRQ1NRu9Ud1Fo4zwUFxiwM4ZUjaLclgIgv8v
5h0urZY/j4994YtC4UvheC53UEAqDKjMWXnjH5u4nQKBgQDlwqSk6St7pAW1lpA+
0OMKQgdDe+W+O2a0LPjaSevCX3Q9ml/ToRH+tmVUGOr2S301GqSRaPdauXBDvE29
HSoD6gCEsT+TocSxyhn0Gg25fMDz3+H7XVOAj+tPg/IWJG8+KxO5gEwucb6Axl3w
NQ29l77SKFgMYitq8N1jjt6LMwKBgQCW0hJzx2dgaYmKrxctWOxfibTaCGBEn4+F
6YwmfGJg+qZ+FU+aBkwaocutIudHogIAOXp6e4J086a6cUwx/Eex1tvTztVa8A/W
8cRmk+DWIIYN4c/wePe3wDluddtRIgh54ukpFsgVsOEEmzp3GAa8fyUA7dVvuJlQ
z1torG11cwKBgQCImppzZiKxR0sRtOwcPOvQLIPPDroAyaZ9l4N5nZurnD8rZT52
P/zH+T/zqUEBoM5XpXiU79ipOznRPALoXo+ddiJKwmuvZe3hWuzlYhwo3VCHbuQY
JFvCQ08/no5vtcfiKZB3qR0iPARs4gP2DkUWJUOSBeSbsD5qPb0TNV2BWwKBgAz+
QBS1YxSNQwotl2OSu5pndKsr+Y8v599zhV1zbc5JCbrm/xqX3EqXEcLytNYZAO8g
BIs0xMJqkzyQsi3EPDD3/6w5r2vMLrEn1vG3X7FSz/m2MIHZCg5MgyYfBSvyMKS/
hbLCga5MtLX+4YSND1eB5KA13SNo1dx+YLOd1zg9AoGAczXhM+n0beuXDhLkiAm3
7Av8lJazrpZg2Oh79IrFJANjVyZZeOVaSfNXPumoDXMZvEMjkIaZZ50IzQfpVdLF
7J0Y/hFCTsX6b3JdkiluniiEh1a2I3tC3+Qa4sSPqKNdHcBJSmmcBcpzRLL5n2zc
bjt4KNf3ZQ3nHvPHnwrd7pg=
-----END RSA PRIVATE KEY-----

View File

@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh1yWs0jhZGt6vscgalbi
7SvjhJbIEUMkAkWpAb3AZKuZSJdRvuor7o7vqt23pomMzlmofx//u/OPHMrudOQq
SbUVLz4kml6ocCAFgB7w9XJC6PccN3ofbmHZp2cfdvnfqClXI2Vs/zOqkIOhmH/J
BNMfMwysNV3fPcusc6Ow6hTZxPQR0sXhTUgIKfjDgT5+19pnQzlpenhi7KlyugU0
xcnktCWh9bdK2uickOcGrt1iqQdtht6SvfrvDEDyozPiV3SGRQNHk9kniKmwdMUX
1OHzpoZ/3l1cjWMLNbPdoT6tS7vP0B3+pukDW5rmpYGkohKP6IChjdbq4/wEbE3W
6QIDAQAB
-----END PUBLIC KEY-----

View File

@ -0,0 +1,38 @@
正式环境
-----BEGIN rsa public key-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdNXFM1ny9+gV+zBwmXc
f21XKilaFdAfHB8959URJkp27JS2iqBuDVSaXQTGJcI6aHk0Cz1zCt2crZX9Z40X
zEhPE8MRLJZfKDgKbg1Gb7c7Dxj7B6+uTbIsGXV+13SE595VL6depxHfgQS425UM
isIPP0isdn7wKey3hJ/COPezOp6/bYwROEy+ZHOMoINWG5Lk3bX0e9axLH1/U19G
5ZqtnVlIqV90y9SiDPnuKu12EZRJ4Z5QrG0/CgAloO/97YLahOmoKDnk7dUIvN/w
A3B80AGP3aXU7cdwrQfXcDXPG2LoyM9MkSrgsBAOQdJsaDHksudEMqEWnDie/TRq
ewIDAQAB
-----END rsa public key-----
-----BEGIN rsa private key-----
MIIEpQIBAAKCAQEAzdNXFM1ny9+gV+zBwmXcf21XKilaFdAfHB8959URJkp27JS2
iqBuDVSaXQTGJcI6aHk0Cz1zCt2crZX9Z40XzEhPE8MRLJZfKDgKbg1Gb7c7Dxj7
B6+uTbIsGXV+13SE595VL6depxHfgQS425UMisIPP0isdn7wKey3hJ/COPezOp6/
bYwROEy+ZHOMoINWG5Lk3bX0e9axLH1/U19G5ZqtnVlIqV90y9SiDPnuKu12EZRJ
4Z5QrG0/CgAloO/97YLahOmoKDnk7dUIvN/wA3B80AGP3aXU7cdwrQfXcDXPG2Lo
yM9MkSrgsBAOQdJsaDHksudEMqEWnDie/TRqewIDAQABAoIBAQCRshNHV2stBrxi
4OX7LM2bqhN0ddcd77fF2Vuh2tIL79Qk/dQFZzDf4M5wH+v/WHCt+XXcqv/fZiX9
PlolTdvVsC3ByGhEzqDHQHwpkN4WQHbe5gj0VOimeQP8dY53BzT5SQm19NzsmJtE
ocoVLXm2U04lttTWAF8S3ky95bS/S1qMbCLlB0ChqCWyZBnLkZgWLK4Vglog3H4H
cClMcPNm/kJNLleQ8QH+CYs8fAABaOuD9dEXJAC4XiKUhyDythWjux9pccjDXJ2u
xIg1t2x+jBrp5uV8MfjxJRAe2sgCj/qcpT9vTbP8yHTshwkVPYBbsd/RlWlo/zXr
8WyN89T5AoGBAN949GqfB/GCjRdf4Bhs57tOc5z9GCZTERcOL07ygma9SLAZ13qK
706IThTz1vgj3ZpOsIZ3UspZiVpXkmDZekWrKK7UhB+TMWLDRzlySXlxLIC++JUT
VG5ugYPNOG2J18qB0o1V/KqUVMr7MBlnxQKTAoHWnImWMZICAC9q2meNAoGBAOvI
0whYFM9zvs5ghIgH3K2z56COPf+V6kb/FlhZhaYFu73YtMu2GxAfwin6ZfTHNypx
KWM5y0en4lC962VbfQYphtL0/PdEhNucRMOTGbLQnoKPDWL7JaDdG0MCkhKnSZlo
okCughG/UNBMHCLDObYLighbkKKMihmidoDH/jQnAoGBALqXYvWXvekwyaAHxLSA
Umk6Exy00zJEz5NBm8y+fpVMXOH1Yc8HLNOUyiWCiC7+u2y5YXmVLkKYyi/tyOIn
FIoRZNG9zmgS3fyJ8vGLdL/6+F6zlhnbXvcqO+gSNZh4rP6AsY6jimnfmoE1hS7h
T0Vb/I7u5BuZleBE3WS6QoyNAoGBAMkd4ovifdW6F833W/SgKCbuJqu3yMBiwpPO
b+PqcGp9x3cXCpgcfBcTz814rVDOQIruPWxK1s8HL67JYKlzEUCZWUxF9iSACIc+
UxUzOx9gfWRF2xhLuvvsvZ056xkIImo9avCbKY0z0B3sXa91MJvMWe/pEoTkNcPJ
5STR8k3PAoGAE334SjfwxpzYG+lcf9Oyli2HbFHO8u6PXhPQ+xgYUh45KeDIWo0Q
j0fmiNrmSYs3Ojs1QtUZMNQWaRmR7Xcysa9pcIFatbbwMfafBO+nROaBbo+bhVKN
VRN1as06j/dVhfYWuwx8BxJjsskllpfcSi7riA6nLrnxbUNktpK6/gs=
-----END rsa private key-----

View File

@ -0,0 +1,38 @@
测试环境
-----BEGIN rsa public key-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAks8Rak/Gt6IuDcjcpKCI
NTj04pWozRaZ1Ryy5DpmtwYW9c7AayIqsIGGTcl8/QiaamTThB2pnn8dZ6o8iCXb
z9zG8Jq8GqX4nm8bT7/y3zaTgV6oScY7mw4hfZPSUv2lHaLij4whIrYCOi4mW+lh
9Ab//0NbJ5XHxRnlYscuOIKs64ss18disWWFwl5IgCVTPsqqlYZgkwYIdE2FpZds
rKYLDY1T16Qwvs+H0rlRZ5yKY8Xhj2x+oU8WygSbFPIZ+sONHyfJ4sxjGRdmxohD
4roNycwuHqjOZJauw3Mdkl0ibJE0oCL5yAf8D7li2aUP/0NRSfb64dfG6RhDH6HQ
QQIDAQAB
-----END rsa public key-----
-----BEGIN rsa private key-----
MIIEogIBAAKCAQEAks8Rak/Gt6IuDcjcpKCINTj04pWozRaZ1Ryy5DpmtwYW9c7A
ayIqsIGGTcl8/QiaamTThB2pnn8dZ6o8iCXbz9zG8Jq8GqX4nm8bT7/y3zaTgV6o
ScY7mw4hfZPSUv2lHaLij4whIrYCOi4mW+lh9Ab//0NbJ5XHxRnlYscuOIKs64ss
18disWWFwl5IgCVTPsqqlYZgkwYIdE2FpZdsrKYLDY1T16Qwvs+H0rlRZ5yKY8Xh
j2x+oU8WygSbFPIZ+sONHyfJ4sxjGRdmxohD4roNycwuHqjOZJauw3Mdkl0ibJE0
oCL5yAf8D7li2aUP/0NRSfb64dfG6RhDH6HQQQIDAQABAoIBAAPOUHJEHS+3iaAb
2/R8oOtYTajuHlEqy9QliVG3XeBSzReUQ5LDcP3gbb3oglABABfQA1fCeRo9y2Jb
nHQfHyK1Y4brTAMY2GgrEzcvD7nPrWVGMfCvre3oIOAji+lQ4A3zohH8nQNMWqRt
e9sYIszzvYE9mshc7q/iavrzlPQsDQhU/yzkW99x95UCw5sqVWXW6ubfIyqphrKC
5Ch7ottruBV1y6CThAZE77O2SR4RRwFKdftXXtXltXAtBvBKq9qpOm5GdY0/zDcK
v75gmLJ4Pom78/+bOp4vVhpYhkCl5aixv2Lpf1Dlvwvaz1FR+HHAFecELLwT29tC
uAi5mQECgYEAwYmGwGGMk97o6rxrQcsobZ44+Hk5FiK8UOmvUlDCWHnJ9GPAkaFH
Lw1+VF4ODnUrOWO55sx15SvYNUfaBieh+jGdBV98zeodETeyc+7DbYkQpaGMRuwl
sMN9pMix0q73TQET9PVholssiT4wUAL5Uy+h04nzUbNzOxLCB93DnhECgYEAwjC9
1JinezngDFXoFaJ2ta+W25QViNlbJCyBxbuf/UmGbZOrJQAZHIunZHqMGNrgp9ro
+z5QhuKfg1pRSdeGC2TwH0D3GiaWsIeYqb7bIFKWuMXIm3klNdNuR1pXIDiB9sfx
jx//1ol5+BO0SrhXZNua6euy74JhiupKSJnEnzECgYBdYsXhuHBDvdC3y5kZkzT7
x9gHlT7FfpdNl6TgXFWaqZGYWjXGT4LwolstzICN212zAHrocgoFPeXCt9vtElyn
RB9XQ18OYQQLlcuHA1PLW9LriQsOAc6h/4J1691aItDzmCyQC4ND+yh/RMG9KeIy
kI5Oa4c8ChH1FDUJ5KkKcQKBgHLbd3xGalFFUxKYwTQCquodmEH53Z7ayMClnoBA
0Il0spEfVYwF+dRbeb/BiBmvZE+D+GeaXPDbG/QKOKhPVNZqdmhV+ZG7H0f8e7xy
yZLdpo5VVak3x12F1+VWNtA0/BHmAydfiufu2nhz1yCW1gIurfsL0QM+/8i1eQhm
AtkRAoGAE9moiNCqQPbDVf9LcChzbsgnXsFbwGpzZtw83C8Xf3aKwPWyVXhHS3Sh
xaJu7uZTmwwzXYTfpyraKdYDJNCTupaZqZlj28xqxDN2fYoSwPpuMM0uyKDmZwBk
IX8kptaMRGorPadI+7UEPfgIjtqYXYeJbChscepcqeu87GjSS1o=
-----END rsa private key-----

View File

@ -88,14 +88,15 @@ func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenId string) (cach
// base64编码 // base64编码
base64Encode := encrypt.Base64Encode(key) base64Encode := encrypt.Base64Encode(key)
// 向游戏人生发送请求 // 向游戏人生发送请求
result := struct { type httpResult struct {
secret string `json:"secret"` Secret string `json:"secret"`
key string `json:"key"` // 该用户的token后续的账号绑定、登录态携带都需要此参数。 Key string `json:"key"` // 该用户的token后续的账号绑定、登录态携带都需要此参数。
}{} }
var result httpResult
resp, err := resty.New().R().SetBody(map[string]string{ resp, err := resty.New().R().SetBody(map[string]string{
"plat_id": s.PlatId, "plat_id": s.PlatId,
"key": base64Encode, "key": base64Encode,
}).SetResult(result).Post(s.keyivUrlMap[s.Mode]) }).SetResult(&result).Post(s.keyivUrlMap[s.Mode])
if err != nil { if err != nil {
err = ecode.Fail.Sub("获取用户信息失败") err = ecode.Fail.Sub("获取用户信息失败")
return return
@ -107,7 +108,7 @@ func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenId string) (cach
} }
decode, err := encrypt.Base64Decode(result.secret) decode, err := encrypt.Base64Decode(result.Secret)
if err != nil { if err != nil {
err = ecode.Fail.Sub("解密用户信息失败") err = ecode.Fail.Sub("解密用户信息失败")
return return
@ -121,15 +122,15 @@ func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenId string) (cach
} }
aesResult := struct { aesResult := struct {
key string `json:"key"` Key string `json:"key"`
iv string `json:"iv"` IV string `json:"iv"`
}{} }{}
if err = json.Unmarshal(plain, &aesResult); err != nil { if err = json.Unmarshal(plain, &aesResult); err != nil {
err = ecode.Fail.Sub("解密用户信息失败") err = ecode.Fail.Sub("解密用户信息失败")
return return
} }
gamelifeCache := model.UserGamelifeCache{Aes: aesResult.key, IV: aesResult.iv, Token: result.key} gamelifeCache := model.UserGamelifeCache{Aes: aesResult.Key, IV: aesResult.IV, Token: result.Key}
// 将用户的 aeskey 和 iv 存储到缓存当中,用于后续请求数据加密, 固定时间 2 小时同时不同用户加上一个随机时间 // 将用户的 aeskey 和 iv 存储到缓存当中,用于后续请求数据加密, 固定时间 2 小时同时不同用户加上一个随机时间
if err = g.Redis().SetEX(ctx, fmt.Sprintf(consts.GameLifeUserKey, popenId), gamelifeCache, int64(consts.GameLifeUserExpire+grand.Intn(1000))); err != nil { if err = g.Redis().SetEX(ctx, fmt.Sprintf(consts.GameLifeUserKey, popenId), gamelifeCache, int64(consts.GameLifeUserExpire+grand.Intn(1000))); err != nil {
err = ecode.Fail.Sub("设置用户信息失败") err = ecode.Fail.Sub("设置用户信息失败")

View File

@ -7,10 +7,11 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"errors" "errors"
"os" "fmt"
"sync"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"os"
"strings"
"sync"
) )
type rsaClient struct { type rsaClient struct {
@ -28,7 +29,7 @@ func init() {
ctx := context.Background() ctx := context.Background()
once.Do(func() { once.Do(func() {
instance = &rsaClient{} instance = &rsaClient{}
err := instance.loadKeys(g.Config().MustGet(ctx, "rsa.publickey").String(), g.Config().MustGet(ctx, "rsa.privatekey").String()) err := instance.loadKeys(g.Config().MustGet(ctx, "gamelife.rsaKey").String())
if err != nil { if err != nil {
panic("加载 RSA 密钥失败: " + err.Error()) panic("加载 RSA 密钥失败: " + err.Error())
} }
@ -80,47 +81,94 @@ func (c *rsaClient) DecryptWithRsaPrivateKey(cipher []byte) ([]byte, error) {
// //
// 返回值: // 返回值:
// - 成功返回 nil否则返回错误信息。 // - 成功返回 nil否则返回错误信息。
func (c *rsaClient) loadKeys(publicKeyPath, privateKeyPath string) error { func (c *rsaClient) loadKeys(keyFilePath string) error {
// 加载公钥 // 读取密钥文件
pubBytes, err := os.ReadFile(publicKeyPath) keyBytes, err := os.ReadFile(keyFilePath)
if err != nil { if err != nil {
return err return fmt.Errorf("读取密钥文件失败: %w", err)
}
pubBlock, _ := pem.Decode(pubBytes)
if pubBlock == nil {
return errors.New("无法解析公钥 PEM 文件")
}
pubKey, err := x509.ParsePKIXPublicKey(pubBlock.Bytes)
if err != nil {
return err
}
var ok bool
if c.publicKey, ok = pubKey.(*rsa.PublicKey); !ok {
return errors.New("公钥不是 RSA 公钥")
} }
// 加载私钥 var pubFound, privFound bool
privBytes, err := os.ReadFile(privateKeyPath) rest := keyBytes
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
// 转换为小写以匹配你的密钥格式
blockTypeLower := strings.ToLower(block.Type)
switch blockTypeLower {
case "rsa public key":
// 尝试解析 PKCS#1 格式的公钥
pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil { if err != nil {
return err // 尝试 PKIX 格式(兼容性处理)
} pub, err := x509.ParsePKIXPublicKey(block.Bytes)
privBlock, _ := pem.Decode(privBytes)
if privBlock == nil {
return errors.New("无法解析私钥 PEM 文件")
}
// 尝试解析 PKCS#8 格式
privKey, err := x509.ParsePKCS8PrivateKey(privBlock.Bytes)
if err != nil { if err != nil {
// 回退尝试 PKCS#1 格式 return fmt.Errorf("无法解析 RSA 公钥: %w", err)
privKey, err = x509.ParsePKCS1PrivateKey(privBlock.Bytes) }
var ok bool
if c.publicKey, ok = pub.(*rsa.PublicKey); !ok {
return errors.New("解析的公钥不是 RSA 公钥")
}
} else {
c.publicKey = pubKey
}
pubFound = true
case "rsa private key":
// 解析 PKCS#1 格式的私钥
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil { if err != nil {
return errors.New("解析私钥失败: 既不是 PKCS#8 也不是 PKCS#1 格式") return fmt.Errorf("无法解析 RSA 私钥: %w", err)
}
c.privateKey = privKey
privFound = true
default:
// 忽略未知的 PEM 块
continue
} }
} }
var ok2 bool
if c.privateKey, ok2 = privKey.(*rsa.PrivateKey); !ok2 { if !pubFound {
return errors.New("私钥不是 RSA 钥") return errors.New("未找到有效的 RSA 钥")
}
if !privFound {
return errors.New("未找到有效的 RSA 私钥")
} }
return nil return nil
} }
// EncryptWithPublicKey 使用公钥加密数据
func (c *rsaClient) EncryptWithPublicKey(plaintext []byte) ([]byte, error) {
if c.publicKey == nil {
return nil, errors.New("公钥未加载")
}
// 使用 OAEP 填充进行加密
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, c.publicKey, plaintext)
if err != nil {
return nil, fmt.Errorf("公钥加密失败: %w", err)
}
return ciphertext, nil
}
// DecryptWithPrivateKey 使用私钥解密数据
func (c *rsaClient) DecryptWithPrivateKey(ciphertext []byte) ([]byte, error) {
if c.privateKey == nil {
return nil, errors.New("私钥未加载")
}
// 使用 OAEP 填充进行解密
plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, c.privateKey, ciphertext)
if err != nil {
return nil, fmt.Errorf("私钥解密失败: %w", err)
}
return plaintext, nil
}