微信小程序获取手机号,golang实现第三方服务
微信小程序无法在前端直接获取用户的手机号,只能获取到aes加密后的手机号信息和一个code。将加密后的手机信息和code传到我们自己写的服务就可以解密了。
解密需要两个步骤:
1.使用code从微信API获取session key。
直接使用以下参数,对api发起get请求
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=APPSECRET&js_code=CODE&grant_type=authorization_code
属性 | 描述 |
appid |
微信小程序的appid,从微信小程序平台获取,每个小程序都不一样 |
secret |
微信小程序的app secret,从微信小程序平台获取,每个小程序都不一样 |
js_code |
小程序前端获取用户手机号信息时的code |
grant_type |
固定值 authorization_code |
2.使用session key解密加密的手机信息。
go语言代码示例
package main import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/json" "fmt" "io/ioutil" "net/http" "github.com/gin-gonic/gin" ) type Reply struct { Code int `json:"code"` Data interface{} `json:"data"` } func main() { gin.SetMode(gin.ReleaseMode) router := gin.Default() //实例化一个gin router.POST("/getnum", getNum) fmt.Println("服务启动...端口为9300") router.Run("127.0.0.1:9300") //监听9300端口 } func getNum(c *gin.Context) { var req struct { EncryptedData string Iv string Code string } err := c.Bind(&req) if err != nil { c.Error(err) } url := "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=" + req.Code + "&grant_type=authorization_code" resp, err := http.Get(url) if err != nil { c.Error(err) } defer resp.Body.Close() s, _ := ioutil.ReadAll(resp.Body) res := make(map[string]string) json.Unmarshal(s, &res) key, _ := base64.StdEncoding.DecodeString(res["session_key"]) iv, _ := base64.StdEncoding.DecodeString(req.Iv) ciphertext, _ := base64.StdEncoding.DecodeString(req.EncryptedData) plaintext := make([]byte, len(ciphertext)) block, err := aes.NewCipher(key) if err != nil { panic(err) } mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(plaintext, ciphertext) plaintext = PKCS7UnPadding(plaintext) fmt.Println("return:", string(plaintext)) c.JSON(http.StatusOK, Reply{http.StatusOK, string(plaintext)}) } // 发送post请求 func post(url, data string) (string, error) { reader := bytes.NewReader([]byte(data)) request, err := http.NewRequest("POST", url, reader) if err != nil { return "", err } defer request.Body.Close() //程序在使用完回复后必须关闭回复的主体 request.Header.Set("Content-Type", "application/json;charset=UTF-8") //必须设定该参数,POST参数才能正常提交,意思是以json串提交数据 client := http.Client{} resp, err := client.Do(request) //Do 方法发送请求,返回 HTTP 回复 if err != nil { return "", err } respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return string(respBytes), nil } func PKCS7Padding(ciphertext []byte) []byte { padding := aes.BlockSize - len(ciphertext)%aes.BlockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func PKCS7UnPadding(plantText []byte) []byte { length := len(plantText) unpadding := int(plantText[length-1]) return plantText[:(length - unpadding)] }