fix
This commit is contained in:
@@ -32,6 +32,9 @@ service main {
|
||||
@doc "wechat h5 auth"
|
||||
@handler wxH5Auth
|
||||
post /user/wxh5Auth (WXH5AuthReq) returns (WXH5AuthResp)
|
||||
|
||||
@handler getSignature
|
||||
post /wechat/getSignature (GetSignatureReq) returns (GetSignatureResp)
|
||||
}
|
||||
|
||||
type (
|
||||
@@ -57,6 +60,18 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
GetSignatureReq {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
GetSignatureResp {
|
||||
AppId string `json:"appId"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
NonceStr string `json:"nonceStr"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
WXH5AuthReq {
|
||||
Code string `json:"code"`
|
||||
|
||||
@@ -1050,6 +1050,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/user/wxh5Auth",
|
||||
Handler: user.WxH5AuthHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/wechat/getSignature",
|
||||
Handler: user.GetSignatureHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
29
app/main/api/internal/handler/user/getsignaturehandler.go
Normal file
29
app/main/api/internal/handler/user/getsignaturehandler.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"hm-server/app/main/api/internal/logic/user"
|
||||
"hm-server/app/main/api/internal/svc"
|
||||
"hm-server/app/main/api/internal/types"
|
||||
"hm-server/common/result"
|
||||
"hm-server/pkg/lzkit/validator"
|
||||
)
|
||||
|
||||
func GetSignatureHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GetSignatureReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := user.NewGetSignatureLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetSignature(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
185
app/main/api/internal/logic/user/getsignaturelogic.go
Normal file
185
app/main/api/internal/logic/user/getsignaturelogic.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"hm-server/app/main/api/internal/svc"
|
||||
"hm-server/app/main/api/internal/types"
|
||||
"hm-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetSignatureLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetSignatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSignatureLogic {
|
||||
return &GetSignatureLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetSignatureLogic) GetSignature(req *types.GetSignatureReq) (resp *types.GetSignatureResp, err error) {
|
||||
// 1. 获取access_token
|
||||
accessToken, err := l.getAccessToken()
|
||||
if err != nil {
|
||||
l.Errorf("获取access_token失败: %v", err)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 获取jsapi_ticket
|
||||
jsapiTicket, err := l.getJsapiTicket(accessToken)
|
||||
if err != nil {
|
||||
l.Errorf("获取jsapi_ticket失败: %v", err)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取jsapi_ticket失败: %v", err)
|
||||
}
|
||||
|
||||
// 3. 生成签名
|
||||
timestamp := time.Now().Unix()
|
||||
nonceStr := l.generateNonceStr(16)
|
||||
signature := l.generateSignature(jsapiTicket, nonceStr, timestamp, req.Url)
|
||||
|
||||
// 4. 返回完整的JS-SDK配置信息
|
||||
return &types.GetSignatureResp{
|
||||
AppId: l.svcCtx.Config.WechatH5.AppID,
|
||||
Timestamp: timestamp,
|
||||
NonceStr: nonceStr,
|
||||
Signature: signature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getAccessToken 获取微信公众号access_token
|
||||
func (l *GetSignatureLogic) getAccessToken() (string, error) {
|
||||
appID := l.svcCtx.Config.WechatH5.AppID
|
||||
appSecret := l.svcCtx.Config.WechatH5.AppSecret
|
||||
|
||||
url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appID, appSecret)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
ErrCode int `json:"errcode"`
|
||||
ErrMsg string `json:"errmsg"`
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(body, &result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if result.ErrCode != 0 {
|
||||
return "", fmt.Errorf("获取access_token失败: errcode=%d, errmsg=%s", result.ErrCode, result.ErrMsg)
|
||||
}
|
||||
|
||||
return result.AccessToken, nil
|
||||
}
|
||||
|
||||
// getJsapiTicket 获取jsapi_ticket
|
||||
func (l *GetSignatureLogic) getJsapiTicket(accessToken string) (string, error) {
|
||||
url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", accessToken)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Ticket string `json:"ticket"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
ErrCode int `json:"errcode"`
|
||||
ErrMsg string `json:"errmsg"`
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(body, &result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if result.ErrCode != 0 {
|
||||
return "", fmt.Errorf("获取jsapi_ticket失败: errcode=%d, errmsg=%s", result.ErrCode, result.ErrMsg)
|
||||
}
|
||||
|
||||
return result.Ticket, nil
|
||||
}
|
||||
|
||||
// generateNonceStr 生成随机字符串
|
||||
func (l *GetSignatureLogic) generateNonceStr(length int) string {
|
||||
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
result := make([]byte, length)
|
||||
for i := 0; i < length; i++ {
|
||||
result[i] = chars[i%len(chars)]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// generateSignature 生成签名
|
||||
func (l *GetSignatureLogic) generateSignature(jsapiTicket, nonceStr string, timestamp int64, urlStr string) string {
|
||||
// 对URL进行解码,避免重复编码
|
||||
decodedURL, err := url.QueryUnescape(urlStr)
|
||||
if err != nil {
|
||||
decodedURL = urlStr
|
||||
}
|
||||
|
||||
// 构建签名字符串
|
||||
params := map[string]string{
|
||||
"jsapi_ticket": jsapiTicket,
|
||||
"noncestr": nonceStr,
|
||||
"timestamp": fmt.Sprintf("%d", timestamp),
|
||||
"url": decodedURL,
|
||||
}
|
||||
|
||||
// 对参数进行字典序排序
|
||||
keys := make([]string, 0, len(params))
|
||||
for k := range params {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// 拼接字符串
|
||||
var signStr strings.Builder
|
||||
for i, k := range keys {
|
||||
if i > 0 {
|
||||
signStr.WriteString("&")
|
||||
}
|
||||
signStr.WriteString(k)
|
||||
signStr.WriteString("=")
|
||||
signStr.WriteString(params[k])
|
||||
}
|
||||
|
||||
// SHA1加密
|
||||
h := sha1.New()
|
||||
h.Write([]byte(signStr.String()))
|
||||
signature := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
return signature
|
||||
}
|
||||
@@ -1465,6 +1465,17 @@ type GetRoleListResp struct {
|
||||
Items []RoleListItem `json:"items"` // 列表
|
||||
}
|
||||
|
||||
type GetSignatureReq struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type GetSignatureResp struct {
|
||||
AppId string `json:"appId"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
NonceStr string `json:"nonceStr"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
type GetWithdrawalReq struct {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
|
||||
Reference in New Issue
Block a user