# wechat-miniprogram **Repository Path**: atyichang/wechat-miniprogram ## Basic Information - **Project Name**: wechat-miniprogram - **Description**: 微信小程序SDK - **Primary Language**: Go - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-13 - **Last Updated**: 2026-05-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 微信小程序 Go SDK > 一个类型安全、易于使用的微信小程序 Go 语言 SDK,提供完整的 API 交互、加密解密和签名验签功能。 ## ✨ 特性 - 🔐 **安全加密**: 内置 AES-256-GCM 加密解密 - ✍️ **签名验签**: RSA-PSS-SHA256 签名验签功能 - 🚀 **登录认证**: 完整的 Code2Session 登录凭证校验 - 🔄 **Token 管理**: 自动缓存和刷新的 Access Token 管理器 - 🛡️ **类型安全**: 完整的类型定义和错误处理 - 🧪 **测试覆盖**: 包含完整的单元测试 ## 📦 安装 ```bash go get gitee.com/atyichang/wechat-miniprogram ``` ## 🚀 快速开始 ### 1. 登录凭证校验 (Code2Session) ```go package main import ( "fmt" "log" "gitee.com/atyichang/wechat-miniprogram" ) func main() { // 创建客户端 client := wechatminiprogram.NewClient( "your-app-id", // 替换为你的 AppID "your-app-secret", // 替换为你的 AppSecret ) // 使用微信小程序前端传来的 login code jsCode := "0f1f2f3f4f5f6f7f8f9f0f1f2f3f4f5f6f7f8f9f" // 调用登录凭证校验接口 resp, err := client.Code2Session(jsCode) if err != nil { log.Printf("登录失败: %v", err) return } // 成功获取用户信息 fmt.Printf("OpenID: %s\n", resp.OpenID) fmt.Printf("SessionKey: %s\n", resp.SessionKey) fmt.Printf("UnionID: %s\n", resp.UnionID) } ``` ### 2. Access Token 管理 ```go package main import ( "fmt" "log" "gitee.com/atyichang/wechat-miniprogram" ) func main() { // 创建 Token 管理器 tokenManager := wechatminiprogram.NewAccessTokenManager( "your-app-id", "your-app-secret", ) // 获取 Access Token(自动缓存和刷新) token, err := tokenManager.GetAccessToken() if err != nil { log.Printf("获取 Access Token 失败: %v", err) return } fmt.Printf("Access Token: %s\n", token) // 后续调用会自动使用缓存的 token,直到过期前5分钟自动刷新 token2, err := tokenManager.GetAccessToken() if err != nil { log.Printf("获取 Access Token 失败: %v", err) return } fmt.Printf("相同的 Token: %v\n", token == token2) // true } ``` ### 3. AES-256-GCM 加密解密 ```go package main import ( "fmt" "log" "gitee.com/atyichang/wechat-miniprogram/security/aes" ) func main() { // 准备数据 key := make([]byte, 32) // 32字节密钥 plaintext := []byte("敏感数据需要加密") additionalData := []byte("额外的认证数据") // 可选 // 生成随机 Nonce nonce, err := aes.GenerateNonce() if err != nil { log.Fatalf("生成 Nonce 失败: %v", err) } // 加密 ciphertext, err := aes.EncryptAES256GCM(key, nonce, plaintext, additionalData) if err != nil { log.Fatalf("加密失败: %v", err) } fmt.Printf("密文: %x\n", ciphertext) // 解密 decrypted, err := aes.DecryptAES256GCM(key, nonce, ciphertext, additionalData) if err != nil { log.Fatalf("解密失败: %v", err) } fmt.Printf("解密后: %s\n", decrypted) // "敏感数据需要加密" } ``` ### 4. RSA-PSS-SHA256 签名验签 ```go package main import ( "fmt" "log" "gitee.com/atyichang/wechat-miniprogram/security/rsa" ) func main() { // 准备私钥和公钥 (PEM 格式) privateKeyPEM := []byte(`-----BEGIN PRIVATE KEY----- 你的私钥内容 -----END PRIVATE KEY-----`) publicKeyPEM := []byte(`-----BEGIN PUBLIC KEY----- 你的公钥内容 -----END PUBLIC KEY-----`) // 解析密钥 privateKey, err := rsa.ParsePEMPrivateKey(privateKeyPEM) if err != nil { log.Fatalf("解析私钥失败: %v", err) } publicKey, err := rsa.ParsePEMPublicKey(publicKeyPEM) if err != nil { log.Fatalf("解析公钥失败: %v", err) } // 构建签名消息 (微信 API 格式) urlPath := "/path/to/api" appid := "your-app-id" timestamp := "1234567890" postData := `{"key":"value"}` message := rsa.BuildSignatureMessage(urlPath, appid, timestamp, postData) // 签名 signature, err := rsa.SignSHA256PSS(privateKey, message) if err != nil { log.Fatalf("签名失败: %v", err) } fmt.Printf("签名: %x\n", signature) // 验签 err = rsa.VerifySHA256PSS(publicKey, message, signature) if err != nil { log.Fatalf("验签失败: %v", err) } fmt.Println("验签成功!") } ``` ## 📚 API 文档 ### Client 客户端 #### `NewClient(appID, appSecret string) *Client` 创建微信小程序客户端实例 **参数:** - `appID`: 微信小程序 AppID - `appSecret`: 微信小程序 AppSecret **返回:** - `*Client`: 客户端实例 #### `Code2Session(jsCode string) (*Code2SessionResponse, error)` 调用微信小程序登录凭证校验接口 **参数:** - `jsCode`: 微信小程序前端通过 `wx.login()` 获取的 code **返回:** - `*Code2SessionResponse`: 登录响应,包含 OpenID、SessionKey、UnionID 等 - `error`: 错误信息 **Code2SessionResponse 结构:** ```go type Code2SessionResponse struct { OpenID string // 用户唯一标识 SessionKey string // 会话密钥 UnionID string // 用户在开放平台的唯一标识符 ErrCode int // 错误码 ErrMsg string // 错误信息 } ``` ### AccessTokenManager #### `NewAccessTokenManager(appID, appSecret string) *AccessTokenManager` 创建 Access Token 管理器 **特性:** - 自动缓存 Access Token - 在过期前 5 分钟自动刷新 - 线程安全(使用读写锁) #### `GetAccessToken() (string, error)` 获取有效的 Access Token **返回:** - `string`: Access Token - `error`: 错误信息 ### AES 加密 #### `EncryptAES256GCM(key, nonce, plaintext, additionalData []byte) ([]byte, error)` 使用 AES-256-GCM 加密数据 **参数:** - `key`: 32 字节密钥 (必须) - `nonce`: 12 字节随机数 (必须) - `plaintext`: 待加密的明文 - `additionalData`: 附加认证数据 (可选) **返回:** - `[]byte`: 密文(包含认证标签) - `error`: 错误信息 #### `DecryptAES256GCM(key, nonce, ciphertextWithTag, additionalData []byte) ([]byte, error)` 使用 AES-256-GCM 解密数据 **参数:** - `key`: 32 字节密钥 (必须) - `nonce`: 12 字节随机数 (必须) - `ciphertextWithTag`: 密文(包含认证标签) - `additionalData`: 附加认证数据 (必须与加密时一致) **返回:** - `[]byte`: 解密后的明文 - `error`: 错误信息 #### `GenerateNonce() ([]byte, error)` 生成符合 AES-GCM 标准的随机 Nonce **返回:** - `[]byte`: 12 字节随机 Nonce - `error`: 错误信息 ### RSA 签名验签 #### `SignSHA256PSS(privateKey, payload []byte) ([]byte, error)` 使用 RSA-PSS-SHA256 对数据进行签名 **参数:** - `privateKey`: PKCS#1 或 PKCS#8 DER 格式的私钥 - `payload`: 待签名的数据 **返回:** - `[]byte`: 签名结果 - `error`: 错误信息 #### `VerifySHA256PSS(publicKey, payload, signature []byte) error` 使用 RSA-PSS-SHA256 验证签名 **参数:** - `publicKey`: PKIX DER 格式的公钥 - `payload`: 原始数据 - `signature`: 签名结果 **返回:** - `error`: 验签成功返回 nil,失败返回错误 #### `BuildSignatureMessage(urlPath, appid, timestamp, postData string) []byte` 构建微信 API 签名/验签的待签名串 **参数:** - `urlPath`: API 路径 - `appid`: 小程序 AppID - `timestamp`: 时间戳字符串 - `postData`: POST 请求的 JSON 数据 **返回:** - `[]byte`: 格式为 `urlpath\nappid\ntimestamp\npostdata` 的字节数组 ## 🔐 安全注意事项 1. **密钥管理**: - 永远不要将 AppSecret 和私钥硬编码在代码中 - 使用环境变量或密钥管理服务存储敏感信息 - 定期轮换密钥 2. **Token 安全**: - Access Token 有过期时间,使用 TokenManager 自动管理 - SessionKey 只在服务器端使用,不要传输到前端 3. **加密最佳实践**: - 每次加密使用新的 Nonce - AES 密钥必须是 32 字节 - RSA 密钥长度建议 2048 位或更长 4. **错误处理**: - 所有 API 调用都应该处理错误 - 不要在日志中记录敏感信息(密钥、Token 等) ## 🧪 测试 ```bash # 运行所有测试 go test ./... # 运行 AES 加密测试 go test ./security/aes # 运行 RSA 签名测试 go test ./security/rsa # 查看测试覆盖率 go test -cover ./... ``` ## 📝 完整示例 查看 [examples/](examples/) 目录获取更多完整的使用示例: - [登录流程完整示例](examples/login_example.go) - [数据加密解密示例](examples/encryption_example.go) - [API 调用签名示例](examples/signature_example.go) ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! ## 📄 许可证 MIT License ## 🔗 相关链接 - [微信小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/) - [微信小程序登录流程](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html) - [微信小程序加密解密](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html) ## 💡 AI 友好说明 本项目特别注重 AI 代码生成的友好性: 1. **完整的类型定义**: 所有结构体和函数都有明确的类型标注 2. **详细的错误处理**: 每个函数都返回具体的错误信息 3. **清晰的文档注释**: 关键函数都有详细的使用说明 4. **完整的示例代码**: 提供可直接运行的使用示例 5. **类型安全**: 充分利用 Go 的类型系统避免运行时错误 这使得 AI 助手(如 Claude、GPT 等)能够更好地理解代码,生成更准确的使用代码和错误处理。