go 验证微信公众号服务器配置


最近接触了一下微信公众号开发,刚好很久很久之前申请过一个公众号,看了下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)
}
,

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注