Files
baseapi/platformapi/lakala/lakala_token.go
2025-11-21 09:09:09 +08:00

360 lines
9.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package lakala
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"io"
"io/ioutil"
"math/big"
"mime/multipart"
"net/http"
"strings"
"time"
)
// IncomingToken 进件api,token获取
func (a *API) IncomingToken() (comingToken string, expiresIn int64, err error) {
result, err := a.AccessAPI(IncomingUrlProd, TokenActive, http.MethodPost, "", map[string]interface{}{
"grant_type": "client_credentials",
"client_id": a.clientId,
"client_secret": a.clientSecret,
})
if err != nil {
return "", 0, err
}
expiresIn, err = utils.TryInterface2Int64(result["expires_in"])
if err != nil {
return "", 0, err
}
a.incomingToken = result["access_token"].(string)
a.incomingExpire = time.Now().Unix() + expiresIn
return a.incomingToken, a.incomingExpire, nil
}
// ModifiedToken 更新token获取
func (a *API) ModifiedToken(userName string, password string) (modifiedToken string, modifiedExpire int64, err error) {
result, err := a.AccessAPI(ModifiedUrlProd, TokenActive, http.MethodPost, "", map[string]interface{}{
"grant_type": "password",
"username": userName,
"password": password,
})
if err != nil {
return "", 0, err
}
modifiedExpire, err = utils.TryInterface2Int64(result["expires_in"])
if err != nil {
return "", 0, err
}
a.modifiedToken = result["access_token"].(string)
a.modifiedExpire = time.Now().Unix() + modifiedExpire
return a.modifiedToken, a.modifiedExpire, nil
}
// FileUpload 文件上传下载 filePath:文件url,由于controller:swagger不支持文件类型
func (a *API) FileUpload(filePath, imgType, sourcechnl, isOcr string) (*UploadImgResp, error) {
client := &http.Client{}
// 获取问价
resp, err := client.Get(filePath)
if err != nil {
return nil, err
}
imgData, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
// 创建一个缓冲区来构建 multipart 请求
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 添加文件到 multipart 请求
part, err := writer.CreateFormFile("file", filePath)
if err != nil {
return nil, err
}
_, err = io.Copy(part, strings.NewReader(string(imgData)))
if err != nil {
return nil, err
}
// 添加其他表单字段
writer.WriteField("imgType", imgType)
writer.WriteField("sourcechnl", sourcechnl)
writer.WriteField("isOcr", isOcr)
// 关闭 writer
err = writer.Close()
if err != nil {
return nil, err
}
// 创建 HTTP 请求
req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s", BaseProdUrl, FileUpload), body)
if err != nil {
return nil, err
}
// 设置 Content-Type 头
a.CheckToken()
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.incomingToken))
// 发送请求
resp, err = client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 读取响应
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
img := &UploadImgResp{}
json.Unmarshal(data, img)
return img, err
}
type UploadImgResp struct {
BatchNo interface{} `json:"batchNo"` // 批量号
Status string `json:"status"` // 00 成功, 01 正在处理中, 02 失败
Url string `json:"url"` // 拉卡拉文件地址
ShowUrl string `json:"showUrl"` // 拉卡拉文件url
Result interface{} `json:"result"` //
}
// AttachmentUpload 附件上传
func (a *API) AttachmentUpload(param *AttachmentImg) (*AttachmentImgResp, error) {
reqParameter := map[string]interface{}{
"reqData": param,
"ver": Version,
"timestamp": utils.Int64ToStr(time.Now().Unix()),
"reqId": utils.GetUUID(),
}
result, err := a.AccessAPISign(SeparateAccountProdUrl, AttachmentUpload, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["retCode"].(string) != Success {
return nil, errors.New(result["retMsg"].(string))
}
bodyResult, err := json.Marshal(result["respData"])
if err != nil {
return nil, err
}
attachment := &AttachmentImgResp{}
if err = json.Unmarshal(bodyResult, attachment); err != nil {
return nil, err
}
return attachment, nil
}
// AttachmentImg 进件附件上传
type AttachmentImg struct {
Version string `json:"version"`
OrderNo string `json:"orderNo"`
OrgCode string `json:"orgCode"`
AttType string `json:"attType"`
AttExtName string `json:"attExtName"`
AttContext string `json:"attContext"`
}
// AttachmentImgResp 进件返回值
type AttachmentImgResp struct {
AttType string `json:"attType"`
OrderNo string `json:"orderNo"`
OrgCode string `json:"orgCode"`
AttFileId string `json:"attFileId"`
}
// signParamRSA 支付签名
func (a *API) signParamPrivateKey(params map[string]interface{}, RSAPrivate string) (sig string, err error) {
block, _ := pem.Decode([]byte(RSAPrivate))
private, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// 签名参数
body, err := json.Marshal(params)
if err != nil {
return "", err
}
//bodyData := base64.StdEncoding.EncodeToString(body)
nonceStr := GenerateSecureRandomString(12)
timeStamp := utils.Int64ToStr(time.Now().Unix())
context := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", a.appID, a.serialNo, timeStamp, nonceStr, string(body))
// 进行rsa加密签名
hashed := sha256.Sum256([]byte(context))
signedData, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey), crypto.SHA256, hashed[:])
if err != nil {
return "", err
}
signData := base64.StdEncoding.EncodeToString(signedData)
authorization := fmt.Sprintf(`LKLAPI-SHA256withRSA appid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"`, a.appID, a.serialNo, timeStamp, nonceStr, signData)
return authorization, nil
}
// GenerateSecureRandomString 获取随机字符串
func GenerateSecureRandomString(length int) string {
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
bytes := make([]byte, length)
charSetSize := big.NewInt(int64(len(charset)))
for i := range bytes {
num, _ := rand.Int(rand.Reader, charSetSize)
bytes[i] = charset[num.Int64()]
}
return string(bytes)
}
func GetOrderNumber(length int) string {
charset := "0123456789"
bytes := make([]byte, length)
charSetSize := big.NewInt(int64(len(charset)))
for i := range bytes {
num, _ := rand.Int(rand.Reader, charSetSize)
bytes[i] = charset[num.Int64()]
}
return utils.Time2TimeStrByFormat(time.Now(), TimeFormat) + string(bytes)
}
type CallBackResult struct {
Code string `json:"code"`
Message string `json:"message"`
}
// CallBackResultInfo 失败回调返回
func CallBackResultInfo(err error) *CallBackResult {
if err == nil {
return &CallBackResult{
Code: "SUCCESS",
Message: "执行成功",
}
}
return &CallBackResult{
Code: "400",
Message: err.Error(),
}
}
/****************************/
const (
MAX_ENCRYPT_BLOCK = 117
MAX_DECRYPT_BLOCK = 128
)
func EncryptByPrivateKey(data []byte, privateKeyStr string) (string, error) {
// 解析私钥
block, _ := pem.Decode([]byte(privateKeyStr))
if block == nil {
return "", errors.New("failed to parse PEM block")
}
privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
rsaPrivateKey := privKey.(*rsa.PrivateKey)
// 分段加密
var encrypted []byte
for offset := 0; offset < len(data); offset += MAX_ENCRYPT_BLOCK {
end := offset + MAX_ENCRYPT_BLOCK
if end > len(data) {
end = len(data)
}
chunk, err := rsa.SignPKCS1v15(nil, rsaPrivateKey, 0, data[offset:end])
if err != nil {
return "", err
}
encrypted = append(encrypted, chunk...)
}
return base64.StdEncoding.EncodeToString(encrypted), nil
}
// DecryptByPublicKey 解密函数:分段解密(公钥解密,需手动实现模幂运算)
func DecryptByPublicKey(ciphertext []byte, publicKeyStr string) ([]byte, error) {
// 解析公钥
block, _ := pem.Decode([]byte(publicKeyStr))
if block == nil {
return nil, errors.New("failed to parse PEM block")
}
pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
rsaPublicKey := pubKey.(*rsa.PublicKey)
n := rsaPublicKey.N // 公钥模数
e := rsaPublicKey.E // 公钥指数
blockSize := rsaPublicKey.Size() // 密钥的字节长度128字节
var result bytes.Buffer
for len(ciphertext) > 0 {
blockLen := blockSize
if len(ciphertext) < blockLen {
blockLen = len(ciphertext)
}
block := ciphertext[:blockLen]
ciphertext = ciphertext[blockLen:]
// 将密文块转换为大整数
c := new(big.Int).SetBytes(block)
// 计算 m = c^e mod n (由于私钥加密公钥解密时需要e和n)
m := new(big.Int).Exp(c, big.NewInt(int64(e)), n)
// 将结果转换为字节数组,并补零到固定长度
mBytes := m.Bytes()
if len(mBytes) < blockSize {
padding := make([]byte, blockSize-len(mBytes))
mBytes = append(padding, mBytes...)
}
// 写入最终结果
result.Write(mBytes)
}
// 移除PKCS1v15填充需要实现填充剥离
// 注意此处简化实际需解析填充结构比如去除00 02和填充字节
return stripPKCS1v15Padding(result.Bytes()), nil
}
// 移除PKCS1v15填充示例逻辑需根据实际填充调整
func stripPKCS1v15Padding(data []byte) []byte {
var newData = make([]byte, 0, len(data))
for i := 0; i < len(data); i++ {
if data[i] == 0x01 || data[i] == 0xFF || data[i] == 0x00 {
continue
}
newData = append(newData, data[i])
}
return newData
}