8
0

Compare commits

...

7 Commits

Author SHA1 Message Date
huangqz
34f70342f4 feat(userlive): 新增批量检查用户封禁状态接口 CheckBatch 2026-06-22 20:01:32 +08:00
huangqz
069f74b60f 新增短信常量 2026-06-22 10:26:34 +08:00
huangqz
854c355456 新增短信内容宏字符串 2026-06-17 17:07:20 +08:00
huangqz
252e5953f3 feat(www,web): 新增 RefreshUserSessionID 与 web.ForceOut
重置密码副作用配套:
- services/www 新增 RefreshUserSessionID(清 www 登录态,apisdk.gaore.com /user/sdk_passport.php)及无凭证 NewClient
- 新建 services/web 包,ForceOut 清官网 web 登录态(web.gaore.com /web/users/force_out)
端点/参数/签名与老综合后台 GaoreSDK 1:1 对齐
2026-06-17 10:05:05 +08:00
huangqz
34fbd24365 封装password edit_pwd接口 2026-06-16 17:18:10 +08:00
huangqz
451be79b39 Merge branch 'master' of https://golib.gaore.com/GaoreGo/gaore-common-sdk-go 2026-06-15 09:01:16 +08:00
huangqz
15a1fb19eb feat(passport): 新增修改/清除用户手机号接口 EditPhone
封装 weedong.php 的 edit_phone 动作,更新分表 user_X 的 telephone(phone 传空字符串即清除手机号),远端返回 ok 即成功。
2026-06-11 15:14:40 +08:00
10 changed files with 382 additions and 1 deletions

View File

@ -1,9 +1,10 @@
package passport
import (
"strings"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
"strings"
)
const (
@ -70,6 +71,34 @@ func (c *Client) DelUserAuth(param DelUserAuthRequestParam) (response string, er
return delUserAuthResponse.GetHttpContentString(), nil
}
// EditPhone
// 修改/清除用户手机号phone 传空字符串即清除),成功返回 "ok"
func (c *Client) EditPhone(param EditPhoneRequestParam) (response string, err error) {
editPhoneRequest := CreateEditPhoneRequest(param)
editPhoneResponse := CreateEditPhoneResponse()
err = c.DoAction(editPhoneRequest, editPhoneResponse)
if err != nil && strings.Contains(err.Error(), "json Unmarshal:") {
return editPhoneResponse.GetHttpContentString(), nil
} else if err != nil {
return "", err
}
return editPhoneResponse.GetHttpContentString(), nil
}
// EditPassword
// 修改/清除用户手机号phone 传空字符串即清除),成功返回 "ok"
func (c *Client) EditPassword(param EditPasswordRequestParam) (response string, err error) {
editPasswordRequest := CreateEditPasswordRequest(param)
editPasswordResponse := CreateEditPasswordResponse()
err = c.DoAction(editPasswordRequest, editPasswordResponse)
if err != nil && strings.Contains(err.Error(), "json Unmarshal:") {
return editPasswordResponse.GetHttpContentString(), nil
} else if err != nil {
return "", err
}
return editPasswordResponse.GetHttpContentString(), nil
}
// GetUserGameSign
// 获取用户登录过的游戏大类
func (c *Client) GetUserGameSign(req *GetUserGameSignRequest) (response *GetUserGameSignResponse, err error) {

View File

@ -235,6 +235,28 @@ func TestDelUserAuth(t *testing.T) {
t.Logf("del user auth result: %s", res)
}
// 测试修改/清除用户手机号(演示调用方式)
// 注意phone 传空字符串即清除手机号,会真实修改账号数据,仅可对测试账号执行。
func TestEditPhone(t *testing.T) {
client, err := NewClient()
if err != nil {
t.Error(err)
return
}
// 调用方式phone 传空串清除手机号,传具体号码则修改为该号码
param := EditPhoneRequestParam{
UserName: "18271216432", // 占位测试账号
Phone: "",
}
res, err := client.EditPhone(param)
if err != nil {
t.Error(err)
return
}
// 远端返回纯文本,"ok" 表示成功
t.Logf("edit phone result: %s", res)
}
// 测试获取用户登陆信息
func TestGetUserLogin(t *testing.T) {
client, err := NewClient()
@ -252,3 +274,24 @@ func TestGetUserLogin(t *testing.T) {
fmt.Printf("raw: %s\n", resp.GetHttpContentString())
fmt.Printf("data: %+v\n, %d", resp.Data, len(resp.Data))
}
// 测试修改密码
func TestEditPassword(t *testing.T) {
client, err := NewClient()
if err != nil {
t.Error(err)
return
}
req := EditPasswordRequestParam{
UserName: "huangqzcs",
Newpwd: "123456789",
}
resp, err := client.EditPassword(req)
if err != nil {
t.Error(err)
return
}
t.Logf("edit phone result: %s", resp)
}

View File

@ -137,3 +137,92 @@ func CreateDelUserAuthResponse() (response *DelUserAuthResponse) {
}
return
}
type EditPhoneRequestParam struct {
UserName string `position:"Body" field:"user_name"`
Phone string `position:"Body" field:"phone"`
}
type EditPhoneResponse struct {
*responses.BaseResponse
}
type EditPhoneRequest struct {
*requests.RpcRequest
UserName string `position:"Body" field:"user_name"`
Phone string `position:"Body" field:"phone"`
Action string `position:"Body" field:"action"`
Flag string `position:"Body" field:"flag"`
Time string `position:"Body" field:"time"`
}
// CreateEditPhoneRequest 修改/清除用户手机号接口
// 远端将分表 user_X 的 telephone 更新为传入的 phone传空字符串即清除手机号
func CreateEditPhoneRequest(param EditPhoneRequestParam) (req *EditPhoneRequest) {
ts := time.Now().Unix()
sign := weeDongGetSign(ts)
req = &EditPhoneRequest{
RpcRequest: &requests.RpcRequest{},
Action: "edit_phone",
Flag: sign,
Time: fmt.Sprintf("%v", ts),
UserName: param.UserName,
Phone: param.Phone,
}
req.InitWithApiInfo(HOST, VERSION, "/weedong.php")
req.Method = requests.POST
return
}
func CreateEditPhoneResponse() (response *EditPhoneResponse) {
response = &EditPhoneResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}
// EditPasswordRequestParam
// 修改密码相关
type EditPasswordRequestParam struct {
UserName string `position:"Body" field:"user_name"`
Newpwd string `position:"Body" field:"newpwd"`
}
type EditPasswordResponse struct {
*responses.BaseResponse
}
type EditPasswordRequest struct {
*requests.RpcRequest
UserName string `position:"Body" field:"user_name"`
Newpwd string `position:"Body" field:"newpwd"`
Action string `position:"Body" field:"action"`
Flag string `position:"Body" field:"flag"`
Time string `position:"Body" field:"time"`
}
// CreateEditPasswordRequest 修改用户密码
func CreateEditPasswordRequest(param EditPasswordRequestParam) (req *EditPasswordRequest) {
ts := time.Now().Unix()
sign := weeDongGetSign(ts)
req = &EditPasswordRequest{
RpcRequest: &requests.RpcRequest{},
Action: "edit_pwd",
Flag: sign,
Time: fmt.Sprintf("%v", ts),
UserName: param.UserName,
Newpwd: utils.Md5(param.Newpwd),
}
req.InitWithApiInfo(HOST, VERSION, "/weedong.php")
req.Method = requests.POST
return
}
func CreateEditPasswordResponse() (response *EditPasswordResponse) {
response = &EditPasswordResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -13,6 +13,7 @@ const (
ReplaceKeyUrl ReplaceKey = "${url}" // 链接
ReplaceKeyUserName ReplaceKey = "${userName}" // 用户名
ReplaceKeyDateTime ReplaceKey = "${dateTime}" // 年月日时分秒
ReplaceKeyPassWord ReplaceKey = "${passWord}" // 密码
)
type Item struct {
@ -54,6 +55,7 @@ const (
TemplateTypeKFOrderAdditional SmsType = "kf_order_additional" // 客服工单完成
TemplateTypeCancelTip SmsType = "cancel_tip" // 提交账号注销申请
TemplateTypeReverseCancel SmsType = "reverse_cancel" // 终止账号注销申请
TemplateTypeResetPassword SmsType = "reset_password" // 重置密码
)
type SendSmsParam struct {

View File

@ -53,3 +53,13 @@ func (c *Client) CreateRemoveBanRuleCacheReq(req *RemoveBanRuleCacheReq) (resp *
}
return
}
// CreateCheckBatchReq 批量检查用户是否被封禁
func (c *Client) CreateCheckBatchReq(req *CheckBatchReq) (resp *CheckBatchResp, err error) {
resp = CreateCheckBatchResp()
err = c.DoAction(req, resp)
if err != nil {
return
}
return
}

View File

@ -158,3 +158,47 @@ func CreateRemoveBanRuleCacheResp() *RemoveBanRuleCacheResp {
BaseResponse: &responses.BaseResponse{},
}
}
// CheckBatchReq
// 批量检查用户是否被封禁(只读,按身份维度匹配现行封禁规则)
type CheckBatchReq struct {
*requests.JsonRequest
}
type CheckBatchReqParam struct {
UserNames []string `json:"user_names"` // 要检查的用户名列表
}
type CheckBatchItem struct {
UserName string `json:"user_name"` // 用户名
Ban bool `json:"ban"` // 是否被封禁
BanRuleId int64 `json:"ban_rule_id"` // 命中的封禁规则id(未命中为0)
BanEndTime string `json:"ban_end_time"` // 封禁结束时间(未命中为空)
}
type CheckBatchResp struct {
*responses.BaseResponse
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
List []CheckBatchItem `json:"list"`
} `json:"data"`
}
func CreateCheckBatchReq(param CheckBatchReqParam) *CheckBatchReq {
req := &CheckBatchReq{
&requests.JsonRequest{},
}
req.InitWithApiInfo(HOST, VERSION, "/api/user_ban/check_batch")
req.Method = requests.POST
marshal, _ := json.Marshal(param)
_ = json.Unmarshal(marshal, &req.JsonParams)
return req
}
func CreateCheckBatchResp() *CheckBatchResp {
return &CheckBatchResp{
BaseResponse: &responses.BaseResponse{},
}
}

42
services/web/client.go Normal file
View File

@ -0,0 +1,42 @@
package web
import (
"strings"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
)
const (
VERSION = "2020-01-01"
)
// HOST 官网 web 服务域名(带 "."SDK 不会再追加 .gaore.com
var HOST = requests.Host{
Default: "web.gaore.com",
}
type Client struct {
sdk.Client
}
func NewClient() (client *Client, err error) {
client = new(Client)
err = client.Init()
return
}
// ForceOut 清除玩家官网 web 登录 session返回远端原始响应
// 对齐老综合后台 GaoreSDK web->force_out
func (c *Client) ForceOut(userName string, ts int64) (response string, err error) {
req := CreateForceOutReq(userName, ts)
resp := CreateForceOutResp()
err = c.DoAction(req, resp)
if err != nil && strings.Contains(err.Error(), "json Unmarshal:") {
// 远端返回非 JSON如纯文本直接取原始响应
return resp.GetHttpContentString(), nil
} else if err != nil {
return "", err
}
return resp.GetHttpContentString(), nil
}

44
services/web/force_out.go Normal file
View File

@ -0,0 +1,44 @@
package web
import (
"fmt"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils"
)
// forceOutSignKey 老综合后台业务层计算 sign 用的固定盐
const forceOutSignKey = "user_session_20220505"
type ForceOutReq struct {
*requests.RpcRequest
}
type ForceOutResp struct {
*responses.BaseResponse
}
// CreateForceOutReq 创建官网强制下线请求
// POST web.gaore.com/web/users/force_outsign=md5(user_name+time+"user_session_20220505")
func CreateForceOutReq(userName string, ts int64) *ForceOutReq {
sign := utils.Md5(fmt.Sprintf("%s%d%s", userName, ts, forceOutSignKey))
req := &ForceOutReq{
RpcRequest: &requests.RpcRequest{},
}
req.InitWithApiInfo(HOST, VERSION, "/web/users/force_out")
req.FormParams = map[string]string{
"user_name": userName,
"time": fmt.Sprintf("%d", ts),
"sign": sign,
}
req.Method = requests.POST
return req
}
func CreateForceOutResp() *ForceOutResp {
return &ForceOutResp{
BaseResponse: &responses.BaseResponse{},
}
}

View File

@ -1,6 +1,8 @@
package www
import (
"strings"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
)
@ -25,6 +27,13 @@ type Client struct {
sdk.Client
}
// NewClient 无凭证客户端(用于自带签名的表单接口,如 refreshUserSessionId
func NewClient() (client *Client, err error) {
client = &Client{}
err = client.Init()
return
}
func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) {
client = &Client{}
err = client.InitWithAccessKey(accesskey, secrect, source)
@ -42,3 +51,17 @@ func (c *Client) GetUserInfo(req *GetPwdRequest) (response *GetPwdResponse, err
err = c.DoAction(req, response)
return
}
// RefreshUserSessionID 刷新用户 session清 www 登录态),返回远端原始响应
func (c *Client) RefreshUserSessionID(uname string) (response string, err error) {
req := CreateRefreshUserSessionIDReq(uname)
resp := CreateRefreshUserSessionIDResp()
err = c.DoAction(req, resp)
if err != nil && strings.Contains(err.Error(), "json Unmarshal:") {
// 远端返回非 JSON如纯文本直接取原始响应
return resp.GetHttpContentString(), nil
} else if err != nil {
return "", err
}
return resp.GetHttpContentString(), nil
}

View File

@ -0,0 +1,55 @@
package www
import (
"fmt"
"time"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils"
)
// 对齐老综合后台 GaoreSDK www->refreshUserSessionId 的固定 appid=20 验签
const (
refreshSessionAppID = "20"
refreshSessionAppKey = "yWpx3hWQHFhSnTCj#20#6KuRKuaAjLJ5sYRy"
)
// refreshSessionHost 老 PHP SDK 打的是 apisdk.gaore.com与本包默认 HOST(apisdk.9ooo.cn) 不同,
// 此处显式固定到 apisdk.gaore.com与老综合后台 1:1 对齐。
var refreshSessionHost = requests.Host{Default: "apisdk.gaore.com"}
type RefreshUserSessionIDReq struct {
*requests.RpcRequest
}
type RefreshUserSessionIDResp struct {
*responses.BaseResponse
}
// CreateRefreshUserSessionIDReq 刷新用户 www session使官网/9ooo 登录态失效)
// POST /user/sdk_passport.phpsign=md5(appkey+time)
func CreateRefreshUserSessionIDReq(uname string) *RefreshUserSessionIDReq {
ts := time.Now().Unix()
sign := utils.Md5(refreshSessionAppKey + fmt.Sprintf("%d", ts))
req := &RefreshUserSessionIDReq{
RpcRequest: &requests.RpcRequest{},
}
req.InitWithApiInfo(refreshSessionHost, VERSION, "/user/sdk_passport.php")
req.FormParams = map[string]string{
"appid": refreshSessionAppID,
"time": fmt.Sprintf("%d", ts),
"do": "refreshUserSessionId",
"uname": uname,
"sign": sign,
}
req.Method = requests.POST
return req
}
func CreateRefreshUserSessionIDResp() *RefreshUserSessionIDResp {
return &RefreshUserSessionIDResp{
BaseResponse: &responses.BaseResponse{},
}
}