做此接口主要因为自己的网站都使用了go语言重写,而不想因为一个自动回复功能而需要保留php服务。
加密解密的源码已经放置到 GitHub上,请自行获取 https://github.com/chenxue4076/go-wechat-encryption
go mod 导入方式
require github.com/chenxue4076/go-wechat-encryption v1.3.6
微信自动回复的api接口 核心代码如下 接口文件 wechat.go 就是url地址路由到的地址
import (
"fmt"
"github.com/kataras/iris/v12"
"repositories"
)
type WeChatController struct {
}
func (c *WeChatController) Get(ctx iris.Context) interface{} {
return repositories.WeChatCheckSignature(ctx)
}
func (c *WeChatController) Post(ctx iris.Context) interface{} {
return repositories.WeChatResponseMsg(ctx)
}
repositories 目录里的处理函数如下:
package repositories
import (
"crypto/sha1"
"encoding/hex"
"encoding/xml"
"errors"
go_wechat_encryption "github.com/chenxue4076/go-wechat-encryption"
"github.com/kataras/iris/v12"
"go-iris-windigniter/configs"
"io/ioutil"
"sort"
"strconv"
"strings"
"time"
)
//验证接口
func WeChatCheckSignature(ctx iris.Context) string {
wxConfig,err := configs.GetWeChatConfig()
if err != nil {
return err.Error()
}
wxConfigYuki := wxConfig["TestWechat"]
serverToken := wxConfigYuki["ServerToken"]
signature := ctx.URLParam("signature")
timeStamp := ctx.URLParam("timestamp")
nonce := ctx.URLParam("nonce")
echostr := ctx.URLParam("echostr")
if echostr != "" {
isValid := checkSignature(signature, timeStamp, nonce, serverToken)
if isValid {
return echostr
}
return "Error Signature"
}
return "Error request"
}
func checkSignature(signature, timeStamp, nonce string, token string) bool {
paramsArray := []string{token, timeStamp, nonce}
sort.Strings(paramsArray)
paramsMsg := ""
for _,value := range paramsArray {
//fmt.Println(value)
paramsMsg += value
}
//sha1
sha1Param := sha1.New()
sha1Param.Write([]byte(paramsMsg))
msg := hex.EncodeToString(sha1Param.Sum([]byte("")))
return msg == signature
}
//微信消息回复接口
func WeChatResponseMsg(ctx iris.Context) string {
//微信配置信息
wxConfig,err := configs.GetWeChatConfig()
if err != nil {
return err.Error()
}
wxConfigYuki := wxConfig["Yuki33521"]
//解密
msgDecryptFormat, err := getDecryptXml(ctx, wxConfigYuki)
if err != nil {
return err.Error()
}
//整理信息
result, err := dealPostInfo(msgDecryptFormat, ctx, wxConfigYuki)
//加密返回
return result
}
func getDecryptXml(ctx iris.Context, wxConfigYuki map[string]string) (msgDecryptFormat go_wechat_encryption.MsgDecryptFormatEvent, err error) {
serverToken := wxConfigYuki["ServerToken"]
serverEncodingAesKey := wxConfigYuki["ServerEncodingAesKey"]
appId := wxConfigYuki["AppId"]
//responseAttentionText := wxConfigYuki["ResponseAttentionText"]
//responseReplyHelp := wxConfigYuki["ResponseReplyHelp"]
signature := ctx.URLParam("signature")
timeStamp := ctx.URLParam("timestamp")
nonce := ctx.URLParam("nonce")
encryptType := ctx.URLParam("encrypt_type")
msgSignature := ctx.URLParam("msg_signature")
postDataXML, err := ioutil.ReadAll(ctx.Request().Body)
if err != nil {
return
}
wxBizMsgCrypt := go_wechat_encryption.Default(serverToken, serverEncodingAesKey, appId)
//解密
xmlMsgBytes, errorCode := wxBizMsgCrypt.DecryptMsg(msgSignature, timeStamp, nonce, postDataXML)
if errorCode != go_wechat_encryption.WXBizMsgCryptOK {
err = errors.New(go_wechat_encryption.WXBizMsgErrorMsg(errorCode))
return
}
ctx.Application().Logger().Info("xmlMsgBytes ",string(xmlMsgBytes))
//解析解密后的xml
err = xml.Unmarshal(xmlMsgBytes, &msgDecryptFormat)
if err != nil {
ctx.Application().Logger().Error("解析XML失败 ", err.Error())
}
ctx.Application().Logger().Info("解析XML ",msgDecryptFormat)
return
}
func dealPostInfo(msgDecryptFormat go_wechat_encryption.MsgDecryptFormatEvent, ctx iris.Context, wxConfigYuki map[string]string) (msg string, err error) {
if msgDecryptFormat.MsgType == "text" {
keyword := msgDecryptFormat.Content
msg,err = showTextResponse(ctx, msgDecryptFormat, keyword, wxConfigYuki)
return
} else if msgDecryptFormat.MsgType == "event" {
}
err = errors.New("Other message type")
return
}
func showTextResponse(ctx iris.Context, msgDecryptFormat go_wechat_encryption.MsgDecryptFormatEvent, text string, wxConfigYuki map[string]string) (msg string, err error) {
if text == "" {
text = wxConfigYuki["ResponseReplyHelp"]
}
timeStampReply := strconv.FormatInt(time.Now().Unix(), 10)
msgType := "text"
msgReplyFormatText := go_wechat_encryption.MsgReplyFormatText{
msgDecryptFormat.FromUserName,
msgDecryptFormat.ToUserName,
timeStampReply,
msgType,
text,
}
resultBytes, err := xml.Marshal(msgReplyFormatText)
if err != nil {
return
}
resultStr := strings.ReplaceAll(string(resultBytes), "MsgReplyFormatText", "xml")
/*textTpl := `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>`
//记得交换 ToUserName 和 FromUserName
resultStr := fmt.Sprintf(textTpl, msgDecryptFormat.FromUserName, msgDecryptFormat.ToUserName, timeStamp, msgType, text)*/
//获取配置
serverToken := wxConfigYuki["ServerToken"]
serverEncodingAesKey := wxConfigYuki["ServerEncodingAesKey"]
appId := wxConfigYuki["AppId"]
timeStamp := ctx.URLParam("timestamp")
nonce := ctx.URLParam("nonce")
//加密
wxBizMsgCrypt := go_wechat_encryption.Default(serverToken, serverEncodingAesKey, appId)
msgBytes,errorCode := wxBizMsgCrypt.EncryptMsg(resultStr, timeStamp, nonce)
if errorCode != 0 {
err = errors.New(go_wechat_encryption.WXBizMsgErrorMsg(errorCode))
return
}
msg = string(msgBytes)
return
}
附件:wechat配置参数
TestWechat:
AppId: wxb9be04dc961ddd0f
AppSecret: 0e06f47e20b436ad6ca2e31762915eba
ServerToken: Windigniter.com
ServerEncodingAesKey: PddAWYnWvqDArOgGelTYk4fqpBcH4fn0JeJuLv68SSe
WeChatId: gh_d29d816879e7
ResponseAttentionText: 终于等到你了
ResponseReplyHelp: 欢迎关注公众号,回复内容
贴出的代码帮助参考使用,另外 https://github.com/chenxue4076/go-wechat-encryption 中的 demo也可以验证 加密解密的正确性
(753)