SHA1大家用的挺多,RSA不多但用的也有,但像支付宝这样要求 SHA1 + RSA的恐怕就没几个了,写起来实在痛苦。而且一搜一片,却没几个能跑起来的。
刚才有个人在QQ上加我,问之前在支付宝集成的帖子里的SHA1withRSA是咋解决的。说实话,不是专门研究加密的,鬼知道报的错是什么玩意,比如这个:
signature, err := rsa.SignPKCS1v15(rand.Reader, this.privateKey,
crypto.SHA1, hashed) //ParsePKCS8PrivateKey err asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:129 isCompound:false}) {optional:false explicit:false application:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier
反正我是真心看的莫名其妙,不过不妨碍我们解决它,由于调用的是系统加密,所以基本可以肯定是套路问题。以下是在beego中集成支付宝的代码,大家可以参考下:
package controllers
import (
"github.com/astaxie/beego"
"fmt"
"net/url"
"time"
"sort"
"encoding/pem"
"crypto/x509"
"mlshop/shopUtils/AliSignUtil"
"net/http"
"io/ioutil"
"mlshop/shopUtils/RandomStrUtil"
"strings"
)
/**
ali第三方授权或用户信息授权后回调地址。授权链接中配置的redirect_uri的值必须与此值保持一致
*/
type AliAnswerController struct {
beego.Controller
}
func (c *AliAnswerController) Get() {
c.EnableRender = false
fmt.Println("AliAnswerController=============get")
//接收manager登录支付宝付款授权页面后 支付宝传递过来的回调信息
auth_code, state := c.GetString("auth_code", "-1"), c.GetString("state")
if state == zfbRandomState {
//根据 auth_code 获取 token
getAliTokenByAuthCode(auth_code)
fmt.Println("============== 开始批量付款 =============")
service := "batch_trans_notify"
partner := "20880000000000"
_input_charset := "UTF-8"
sign_type := "RSA"
notify_url := "http://www.xxxx.com/xxx"
account_name := "130000000"//todo 付款方的支付宝账户名
detail_data := "111110^xxxx^name^0.01^beizhu0"//todo 付款的详细数据 格式为:流水号1^收款方账号1^收款账号姓名1^付款金额1^备注说明1|流水号2^收款方账号2^收款账号姓名2^付款金额2^备注说明2。
batch_no := RandomStrUtil.GetRandomString(32)
batch_num := "1"//付款总笔数
batch_fee := "0.01"//付款总金额
email := "xxxx@sina.com"//付款方的支付宝账号,支持邮箱和手机号2种格式
pay_date := time.Now().Format(TIMELAYOUT3)//YYYYMMDD
m := make(map[string]interface{})
m["service"] = service
m["partner"] = partner
m["_input_charset"] = _input_charset
m["sign_type"] = sign_type
m["notify_url"] = notify_url
m["account_name"] = account_name
m["detail_data"] = detail_data
m["batch_no"] = batch_no
m["batch_num"] = batch_num
m["batch_fee"] = batch_fee
m["email"] = email
m["pay_date"] = pay_date
sign := aliPaySign(m)//签名
requestLine := strings.Join([]string{"https://mapi.alipay.com/gateway.do",
"?service=" + service,
"&partner=" + partner,
"&_input_charset=" + _input_charset,
"¬ify_url=" + url.QueryEscape(notify_url),
"&sign_type=" + sign_type,
"&sign=" + sign,
"&email=" + email,
"&pay_date=" + pay_date,
"&batch_no=" + batch_no,
"&batch_num=" + batch_num,
"&account_name=" + url.QueryEscape(account_name),
"&batch_fee=" + batch_fee,
"&detail_data=",
url.QueryEscape(detail_data)}, "")
c.Redirect(requestLine, 302)
//data := make(url.Values)
//data["service"] = []string{service}
//data["partner"] = []string{partner}
//data["_input_charset"] = []string{_input_charset}
//data["sign_type"] = []string{sign_type}
//data["notify_url"] = []string{notify_url}
//data["account_name"] = []string{account_name}
//data["detail_data"] = []string{detail_data}
//data["batch_no"] = []string{batch_no}
//data["batch_num"] = []string{batch_num}
//data["batch_fee"] = []string{batch_fee}
//data["email"] = []string{email}
//data["pay_date"] = []string{pay_date}
//data["sign"] = []string{sign}
//
//
////把批量付款发送给目标服务器
//_, err := http.PostForm("https://openapi.alipay.com/gateway.do", data)
//if err != nil {
// fmt.Println("批量付款出现错误",err.Error())
// return
//}else {
// fmt.Println("批量付款完毕")
//}
fmt.Println("============== 结束批量付款 =============")
} else {
fmt.Println("接收到的支付宝回调发现state不一致 ", state, " ", zfbRandomState)
}
}
func getAliTokenByAuthCode(auth_code string) {
fmt.Println("接收到的auth_code = ", auth_code)
app_id := beego.AppConfig.String("ali_appId")
method := "alipay.system.oauth.token"
charset := "GBK"
timestamp := time.Now().Format(TIMELAYOUT)
version := "1.0"
grant_type := "authorization_code"
sign_type := "RSA"
code := auth_code
m := make(map[string]interface{})
m["app_id"] = app_id
m["method"] = method
m["charset"] = charset
m["timestamp"] = timestamp
m["version"] = version
m["grant_type"] = grant_type
m["code"] = code
m["sign_type"] = sign_type
//换取 token
data := make(url.Values)
data["app_id"] = []string{app_id}
data["method"] = []string{method}
data["charset"] = []string{charset}
data["sign_type"] = []string{sign_type}
data["timestamp"] = []string{timestamp}
data["sign"] = []string{aliPaySign(m)}//使用RSA进行签名
data["version"] = []string{version}
data["grant_type"] = []string{grant_type}
data["code"] = []string{code}
//把post表单发送给目标服务器 获取token
res, err := http.PostForm("https://openapi.alipay.com/gateway.do", data)
if err != nil {
fmt.Println(err.Error())
return
}
defer res.Body.Close()
bodyBytes, err := ioutil.ReadAll(res.Body)//其中含有 token
fmt.Println("把post表单发送给目标服务器 获取token 返回的数据---", string(bodyBytes), err)
}
func aliPaySign(mReq map[string]interface{}) string {
//STEP 1, 对key进行升序排序.
sorted_keys := make([]string, 0)
for k, _ := range mReq {
sorted_keys = append(sorted_keys, k)
}
sort.Strings(sorted_keys)
//STEP2, 对key=value的键值对用&连接起来,略过空值
var signStrings string
for i, k := range sorted_keys {
//fmt.Printf("k=%v, v=%v\n", k, mReq[k])
value := fmt.Sprintf("%v", mReq[k])
if value != "" {
if i != (len(sorted_keys) - 1) {
signStrings = signStrings + k + "=" + value + "&"
} else {
signStrings = signStrings + k + "=" + value//最后一个不加此符号
}
}
}
fmt.Println("生成的待签名---->", signStrings)
//============================= 开始签名 ==================================
block, _ := pem.Decode([]byte(`-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCsAocILoBYZqhMYDg40AFZTUiFjcSxwrUXOF0rgw8hh98tP+Ox
4awokuF+FJn8qN/9k9gFz9j7zM694vNv976W60k2ye6uiQdQy/gOJh+ciFME3kAH
QoyvuItKRec+3cEhwblpuY7Gchk0mk22WXWyAHuNGXcCMGSJo9ugGnPDUwIDAQAB
AoGARDgcZdpLfMP6K5Bdu+qDHm/QO2emgvm96J+qE/++mIXStZeJLptaNB1M4Tw6
dkJj06Y3Htb4L6ViuVyxP875/yqKocNur4KeoTLC/t+9L7f6jey7GCvWlCcpp97A
NiVCPILG+7Py2+xGyv0tQT+98yJqTb0yA0nIsmq1XpmjkQECQQDUmVH8L6mJvyzj
xDA32jLKoQLWyJTvzkBxeTnsuTL6GqXEcj9HN0Q1qEyTl/DcN5YfACL4XevV1NNV
s6CrKEojAkEAzx/5d3aAI3dg9VHfAcWdiUZ5uTbx+qpDfZ4CtoyhEfolRGTiy2SC
y9GDrtpY3NO1mm+D5lIM3HPbTgAxtvm9EQJADmI5K8jFva4TiW1ynbTDjvYJzSJR
AVCBB6xeAOgezNEUug/IvDa/BKpYU/wJrbyNCZfmxnqE87ise7Xlfu8A5QJBAJTP
Bx9SLvvMMAfwm0UdonJXBOsR08Zg/35HwPFAlhRhYNcDmIHCo8olq/M7Am8dV7Mt
/VjDiGP2hRBESXOJd9ECPxeHMhK4prFTN1N/+fHcnbB61P89mIsH5ff38D9uEwa/
sLqen0K1ibjhgbcs0LjoVklK9fxJ5AK7SwU0Oxaq0w==
-----END RSA PRIVATE KEY-----
`))
if block == nil {
fmt.Println("rsaSign private_key error")
return ""
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
fmt.Printf("x509.ParsePKCS1PrivateKey-------privateKey----- error : %v\n", err)
return ""
} else {
//fmt.Println("x509.ParsePKCS1PrivateKey-------privateKey-----", privateKey)
}
result, err := alipay.RsaSign(signStrings, privateKey)
fmt.Println("alipay.RsaSign=========", result, err)
return result
}
func (c *AliAnswerController) Post() {
c.Ctx.WriteString("success")
}
/**
* RSA签名
* @param $data 待签名数据
* @param $private_key_path 商户私钥文件路径
* return 签名结果
*/
func RsaSign(origData string, privateKey *rsa.PrivateKey) (string, error) {
h := sha1.New()
h.Write([]byte(origData))
digest := h.Sum(nil)
s, err := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA1, digest)
if err != nil {
fmt.Errorf("rsaSign SignPKCS1v15 error")
return "", err
}
data := base64.StdEncoding.EncodeToString(s)
return string(data), nil
}
如果,当然希望没有这个如果,按照上面的法子依然存在问题,大家可以去github搜下go alipay,再试试看吧。