下图是获取支付宝小程序用户信息的流程图
由于支付宝小程序更新所以后来申请的小程序没有alipay.user.info.share的访问权限,所以后台的工作就是根据前台的code请求授权平台换取userid, 然后再根据项目需求,前端获取详细信息返回给后台储存到数据库里。
本来想用拼接字符串的方式加参数,但是就是报sign有问题的错,然后问了客服,给我截了下面这张图
然后查go里面 encode的方法url.values的Encode()方法好像最方便,所以建议参数用url.values方法添加
v := url.Values{}
v.Set("app_id", env.ZfbAppId)// 项目的appid
v.Set("charset", "UTF-8")
v.Set("code", authCode)// 前端传的code
v.Set("grant_type", "authorization_code")
v.Set("method", "alipay.system.oauth.token")
v.Set("sign_type", "RSA2")
v.Set("timestamp", now)//时间 2006-01-02 15:04:05 格式
v.Set("version", "1.0")
然后就是签名,签名就是去掉表示签名的sign字段,然后去掉空字段、空格再把字段根据ASCII排序最后根据要求的格式加密再Base64一下就行了,由于没有官方go语言的SDK,所以需要自行签名
我用的是普通公钥方式,下图是支付宝需要的签名的加密编码方式
百度了很久最后找别人总结出了一个方法。。。
func GetLoginSign(param url.Values, privateKey *rsa.PrivateKey) (string, error) {
//param就是url参数,privateKey 是私钥
if param == nil {
param = make(url.Values, 0)
}
var pList = make([]string, 0, 0)
for key := range param {
var value = strings.TrimSpace(param.Get(key)) //*去空格 签名必须有的一步
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList) //*根据ASCII码排序 签名必须有的一步
var src = strings.Join(pList, "&")
sig, err := crypto4go.RSASignWithKey([]byte(src), privateKey, crypto.SHA256)
if err != nil {
return "", err
}
s := base64.StdEncoding.EncodeToString(sig)
return s, nil
}
这个方法的私钥也需要处理一下
privateKey, _ = crypto4go.ParsePKCS1PrivateKey(crypto4go.FormatPKCS1PrivateKey(zfbPrivateKey))// zfbPrivateKey 是配置的私钥,privateKey是上面方法需要的参数
方法返回的就是需要的sign
然后就是加上sign字段,再对url进行encode,最后请求,再根据需要处理返回的参数
v.Set("sign", s) //s是GetLoginSign方法返回的sign
sth := v.Encode()//对请求的参数进行encode
aUrl := "https://openapi.alipay.com/gateway.do?" + sth
resp, err := http.Get(aUrl)
if err != nil {
response.Response(c, 201, &gin.H{"message": "login taken 获取失败"})
return
}
body, _ := ioutil.ReadAll(resp.Body)