最近接触了一下微信公众号开发,刚好很久很久之前申请过一个公众号,看了下API文档,用go实现了一个简单的验证微信服务器的功能。
下面的代码可以通过微信服务器的验证。
只需要配置 config.json文件即可,config.json和main.go文件处于同一目录层级,config.json格式文件配置如下:
{
"token":"XXX",
"port":"7001"
}
其中token需要在微信公众平台获取相关信息。
port 则是你使用的监听接口,nginx反向代理到该端口。
运行时,输入
go run main.go config.json 即可
代码:
package main
import (
"crypto/sha1"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"sort"
"strings"
)
const wx_params_timestamp string = "timestamp"
const wx_params_signature string = "signature"
const wx_params_nonce string = "nonce"
const wx_params_echostr string = "echostr"
const wx_access_token_key string = "access_token"
const wx_access_token_time_key string = "expires_in"
const wx_access_token_error_code string = "errcode"
const wx_access_token_error_msg string = "errmsg"
//
var wx_gzh_token_str string
type SConsConfig struct {
Token string `json:"token"`
Port string `json:"port"`
}
func NewJsonStruct() *SConsConfig {
return &SConsConfig{}
}
func (jst *SConsConfig) LoadConfig(fileName string, v interface{}) {
data, err := ioutil.ReadFile(fileName)
if err != nil {
return
}
err = json.Unmarshal(data, v)
if err != nil {
return
}
}
func ParseSconsConfig(fileName string) (v SConsConfig, err error) {
JsonParse := NewJsonStruct()
v = SConsConfig{}
JsonParse.LoadConfig(fileName, &v)
return v, nil
}
func makeSignature(timestamp string, nonce string) string {
//1. 将 plat_token、timestamp、nonce三个参数进行字典序排序
sl := []string{wx_gzh_token_str, timestamp, nonce}
sort.Strings(sl)
//2. 将三个参数字符串拼接成一个字符串进行sha1加密
s := sha1.New()
io.WriteString(s, strings.Join(sl, ""))
return fmt.Sprintf("%x", s.Sum(nil))
}
func CheckSignature(r *http.Request) (bool, string) {
r.ParseForm()
log.Println("start parse require params")
for k, v := range r.Form {
log.Println("k=", k, ",v=", v)
}
timestamp := ""
if len(r.Form[wx_params_timestamp]) > 0 {
timestamp = r.Form[wx_params_timestamp][0]
log.Println(wx_params_timestamp, "=", timestamp)
}
signature := ""
if len(r.Form[wx_params_signature]) > 0 {
signature = r.Form[wx_params_signature][0]
log.Println(wx_params_signature, "=", signature)
}
nonce := ""
if len(r.Form[wx_params_nonce]) > 0 {
nonce = r.Form[wx_params_nonce][0]
log.Println(wx_params_nonce, "=", nonce)
}
echostr := ""
if len(r.Form[wx_params_echostr]) > 0 {
echostr = r.Form[wx_params_echostr][0]
log.Println(wx_params_echostr, "=", echostr)
}
my_signature := makeSignature(timestamp, nonce)
log.Println("my signature is ", my_signature)
if signature == my_signature {
return true, echostr
} else {
return false, echostr
}
}
type wx_token_require_handler struct{}
func (h *wx_token_require_handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println("check require is from wx server or not")
flag, echostr := CheckSignature(r)
if flag {
w.Write([]byte(echostr))
} else {
log.Println("require not from wx server,please check")
}
}
func InitGlobal() {
wx_gzh_token_str = ""
}
func HttpCheckServer(checkPort string) {
http.Handle("/", &wx_token_require_handler{})
port := "0.0.0.0:" + checkPort
log.Println("start listen port:", checkPort)
http.ListenAndServe(port, nil)
}
func main() {
log.Println("start gzh token center")
log.Println("param format: port srv_port")
arg_num := len(os.Args)
if arg_num < 2 {
log.Println("please input the port and token str")
os.Exit(1)
}
configFile := os.Args[1]
config, err := ParseSconsConfig(configFile)
if nil != err {
log.Println("parse config error,err=", err)
os.Exit(1)
}
InitGlobal()
wx_gzh_token_str = config.Token
HttpCheckServer(config.Port)
}