微信分享第三方连接(H5页面)自定义页面 一、准备工作 二、

一、准备工作

  • 一个已备案的网站
  • 一个已认证的公众号(注意,个人权限是不可以的,需要企业权限)。

确保你有一个企业级的微信公众号,并完成企业认证。个人公众号可能无法获取全部接口权限。

  • 获取AppID和AppSecret

在微信公众平台登录后,进入“开发”部分,选择“基本配置”,在这里你可以找到你的AppID和AppSecret。

二、微信公众号后台设置

  • 设置JS接口安全域名:
    进入公众号设置的“功能设置”中,填写“JS接口安全域名”。需确保你的网页服务部署在此域名下,且该域名已通过ICP备案。
  • 设置IP白名单:
    在“安全中心”或“开发者中心”设置服务器IP白名单,以便微信服务器能够与之通信。

三、获取签名(含代码)

3.1 获取access_token

  • 接口说明:

使用你的AppID和AppSecret,通过GET请求到api.weixin.qq.com/cgi-bin/tok…

参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):

官方文档:developers.weixin.qq.com/doc/offiacc…

  • golang代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
go复制代码/*
获取小程序全局唯一后台接口调用凭据:
https://developers.weixin.qq.com/minigame/dev/api-backend/open-api/access-token/auth.getAccessToken.html
*/
package weixinclient

import (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
)

type AccessTokenVo struct {
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
Errcode int64 `json:"errcode"`
Errmsg string `json:"errmsg"`
}

func GetAccessToken(c *gin.Context) (*AccessTokenVo, error) {
ctx := commonx.GetTrace(c)

ps := fmt.Sprintf("grant_type=client_credential&appid=%s&secret=%s", config.BookAppid, config.BookSecret)

ep := getEndPoint("GetAccessToken")
resp, err := doGet(c, ep, ps, nil)
dlog.Infof("%v||GetSessionBycode resp=%v,err=%v", ctx, resp, err)
if err != nil || len(resp) == 0 {
return nil, errors.New("call API(GetAccessToken) fail")
}

var vo AccessTokenVo
err = json.Unmarshal(resp, &vo)
if err != nil || vo.Errcode > 0 {
err = fmt.Errorf("err=%v", vo.Errmsg)
return nil, err
}

return &vo, nil
}

返回示例:

1
2
3
4
json复制代码{
"access_token": "80_PR606SNAcwOIyhsRuuOVC11eHDiy1ZqKMiWn6JoxYZH3ANGt13s5DWgiWtIbk0JAxn5LBKyZBMK5-cP5q_NBvTVdFtIf9utExtktae_7c1t4Wm9aBkEd5fuYpw4MMQfAHARRV",
"expires_in": 7200
}

3.2 获取jsapi_ticket

  • 接口说明:

使用上一步获取的access_token,通过GET请求到api.weixin.qq.com/cgi-bin/tic…

参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token)

官方文档:developers.weixin.qq.com/doc/offiacc…

  • 请求方式:
1
2
3
4
bash复制代码请求方式:GET
请求参数:上一步获取到的 access_token
请求地址:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
注意:有效期7200秒, 这里建议将 access_token 和 jsapi_ticket 都在服务器端进行获取并缓存,前端通过接口调取结果
  • jsapi_ticket 说明:

jsapi_ticket是公众号用于调用微信 JS 接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的 api 调用次数非常有限,频繁刷新jsapi_ticket会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket (这里建议将 access_token 和 jsapi_ticket 都在服务器端进行获取并缓存,前端通过接口调取结果)。

  • golang代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
go复制代码package weixinclient

import (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
)

type GetticketVo struct {
Ticket string `json:"ticket"`
ExpiresIn int64 `json:"expires_in"`
Errcode int64 `json:"errcode"`
Errmsg string `json:"errmsg"`
}

func Getticket(c *gin.Context, accessToken string) (*GetticketVo, error) {
ctx := commonx.GetTrace(c)

ps := fmt.Sprintf("access_token=%s&type=jsapi", accessToken)

ep := getEndPoint("Getticket")

resp, err := doGet(c, ep, ps, nil)
dlog.Infof("%v||Getticket resp=%v,err=%v", ctx, resp, err)
if err != nil || len(resp) == 0 {
return nil, errors.New("call API(Getticket) fail")
}

var vo GetticketVo
err = json.Unmarshal(resp, &vo)
if err != nil || vo.Errcode > 0 || vo.Errmsg != "ok" {
err = fmt.Errorf("err=%v", vo.Errmsg)
return nil, err
}

return &vo, nil
}

成功返回如下JSON:

1
2
3
4
5
6
json复制代码{
"errcode":0,
"errmsg":"ok",
"ticket":"caLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

3.3 根据获取到的 ticket 来生成签名

  • 签名说明

微信开发中,ticket 通常用于获取 JS-SDK 的配置参数,包括签名(signature)。这些参数使得你能够在网页上使用微信的 JS-SDK。以下是一个基本的步骤说明如何使用获取到的 ticket 来生成签名:

准备用于签名的参数:nonceStr(随机字符串), timestamp(时间戳), url(当前网页的 URL,不包含 # 及其后面部分)和 jsapi_ticket

将这些参数按照字段名的ASCII 码从小到大排序(字典序),并且使用 URL 键值对的格式(即 key1=value1&key2=value2…)拼接成字符串。
对拼接后的字符串进行 SHA1 加密,得到的结果即是签名(signature)。

  • golang代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
go复制代码package main  

import (
"crypto/sha1"
"encoding/hex"
"fmt"
"sort"
"strings"
"time"
)

// GenerateSignature 生成微信JS-SDK的签名
func GenerateSignature(nonceStr, url, jsapiTicket string) string {
// 实时获取当前时间戳
timestamp := fmt.Sprintf("%d", time.Now().Unix())

// 准备用于签名的原始数据
params := map[string]string{
"jsapi_ticket": jsapiTicket,
"noncestr": nonceStr,
"timestamp": timestamp,
"url": url,
}

// 对参数名进行排序并拼接
var keys []string
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)

var signStrings []string
for _, key := range keys {
signStrings = append(signStrings, fmt.Sprintf("%s=%s", key, params[key]))
}
signString := strings.Join(signStrings, "&")

// 使用SHA1进行签名
h := sha1.New()
h.Write([]byte(signString))
signature := hex.EncodeToString(h.Sum(nil))

return signature
}

func main() {
nonceStr := "Wm3WZYTPz0wzccnW" // 这个应该是随机生成的字符串
url := "http://mp.weixin.qq.com?params=value" // 你的网页URL
jsapiTicket := "bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA" // 从微信服务器获取的jsapi_ticket

// 生成签名
signature := GenerateSignature(nonceStr, url, jsapiTicket)
fmt.Println("生成的签名是:", signature)
}

在这个示例中,GenerateSignature 函数接受四个参数:nonceStr(随机字符串),timestamp(时间戳),url(当前网页的URL),和jsapiTicket(从微信服务器获取的票据)。函数内部会对这些参数进行字典排序,拼接成一个待签名的字符串,然后使用SHA1算法生成签名。

请注意,为了简化示例,这里直接提供了nonceStr、timestamp、url和jsapiTicket的示例值。在实际应用中,我们需要根据具体情况动态获取这些值。特别是jsapiTicket,你需要先从微信服务器获取。

最后,main 函数中调用了 GenerateSignature 并打印出了生成的签名。我们可以将这段代码集成到我们的Go应用中,并根据需要进行适当的修改和调整。

  • noncestr 的含义是什么?应该如何动态获取?

noncestr是一个随机字符串,通常用于确保请求的唯一性和安全性。在微信JS-SDK、微信支付等接口中,noncestr 作为一个重要的参数,用于防止重放攻击和确保请求的时效性。

在微信开发中,noncestr 通常需要你自己生成,并确保其唯一性和随机性。以下是几种生成 noncestr 的方法:

  1. 使用随机数或UUID:
    你可以使用编程语言中的随机数生成函数或者UUID生成库来创建一个唯一的字符串。例如,在Go语言中,你可以使用crypto/rand库生成一个随机数,并将其转换为字符串,或者使用第三方库如github.com/google/uuid来生成一个UUID。
  2. 时间戳结合随机数:
    为了增加noncestr的复杂性,你也可以将当前的时间戳与随机数结合起来使用。这样既可以保证每次请求的noncestr都是唯一的,也能通过时间戳增加一定的时效性验证。
  3. 使用安全的随机数生成器:
    在安全性要求较高的场景下,应使用安全的随机数生成器来产生noncestr,以确保其不可预测性。

golang动态获取 noncestr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
go复制代码package main  

import (
"crypto/rand"
"encoding/hex"
"fmt"
"log"
)

// GenerateNonceStr 生成一个随机的 noncestr
func GenerateNonceStr(length int) (string, error) {
bytes := make([]byte, length/2) // 因为一个字节可以表示为两个16进制数字
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}

func main() {
nonceStr, err := GenerateNonceStr(32) // 生成一个32个字符长的noncestr
if err != nil {
log.Fatalf("Failed to generate nonceStr: %v", err)
}
fmt.Println("Generated nonceStr:", nonceStr)
}

得到的签名:

1
复制代码e851776f519a6c8d716bc61a5dec87b042d14c3e

四、H5页面配置与分享设置

注意:从这一步开始,后面的部分属于前端工作

4.1 引入微信JS-SDK

在需要调用 JS 接口的页面引入如下 JS文件,(支持https):res.wx.qq.com/open/js/jwe…

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:res2.wx.qq.com/open/js/jwe…

备注:支持使用 AMD/CMD 标准模块加载方法加载

4.2 通过 config 接口注入权限验证配置

所有需要使用 JS-SDK 的页面必须先注入配置信息,否则将无法调用(同一个 url 仅需调用一次,对于变化 url 的SPA的web app可在每次 url 变化时进行调用,目前 Android 微信客户端不支持 pushState 的H5新特性,所以使用 pushState 来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

注意:

  • 引入JS文件后,直接执行下列代码
  • debug: true 用来调试的,如果不想alert弹出,改成false即可
  • alert 弹出框中 errMsg 不一定就是错误,知识提示信息,例如 updateAppMessageShareData:ok 代表的是updateAppMessageShareData接口是没有问题的。
  • 签名用的 noncestr 和 timestamp 必须与 wx.config 中的 nonceStr 和 timestamp 相同。
  • jsApiList 接口列表:developers.weixin.qq.com/doc/offiacc…
  • jsApiList 接口列表 例如 wx.updateAppMessageShareData({ 配置 }) jsApiList填写 [‘updateAppMessageShareData’] 即可
1
2
3
4
5
6
7
8
csharp复制代码wx.config({
debug: true, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名(这里用上面第三步得到的签名)
jsApiList: [] // 必填,需要使用的 JS 接口列表
});

4.3 通过 ready 接口处理成功验证

在wx.ready函数中配置onMenuShareTimeline、onMenuShareAppMessage等接口实现微信分享功能,并设置自定义的分享标题、描述、缩略图及链接。

1
2
3
lua复制代码wx.ready(function(){
// config信息验证后会执行 ready 方法,所有接口调用都必须在 config 接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在 ready 函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在 ready 函数中。
});

4.4 通过 error 接口处理失败验证

使用wx.error函数处理验证失败的情况。

1
2
3
lua复制代码wx.error(function(res){
// config信息验证失败会执行 error 函数,如签名过期导致验证失败,具体错误信息可以打开 config 的debug模式查看,也可以在返回的 res 参数中查看,对于 SPA 可以在这里更新签名。
});

4.5 js代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
javascript复制代码// 模拟从后端获取签名等配置信息的函数  
function getWechatConfig(url) {
// 通常情况下,以下代码应由后端服务生成并返回给前端
// 这里仅为示例,实际项目中,signature, nonceStr, timestamp 应该在服务器端生成
const appId = 'YOUR_APP_ID'; // 替换为你的AppID
const jsApiList = ['onMenuShareTimeline', 'onMenuShareAppMessage'];

// 以下为模拟数据,实际开发中应由服务器端提供
const nonceStr = 'Wm3WZYTPz0wzccnW'; // 随机字符串
const timestamp = Math.floor(Date.now() / 1000).toString(); // 当前时间戳
const signature = 'SOME_SIGNATURE_STRING'; // 签名,应由后端根据算法生成

return {
appId,
nonceStr,
timestamp,
signature,
jsApiList
};
}

// 调用微信JS-SDK配置
function initWechatSDK() {
const currentUrl = encodeURIComponent(location.href.split('#')[0]);
const config = getWechatConfig(currentUrl);

wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: config.appId, // 必填,公众号的唯一标识
timestamp: config.timestamp, // 必填,生成签名的时间戳
nonceStr: config.nonceStr, // 必填,生成签名的随机串
signature: config.signature, // 必填,签名
jsApiList: config.jsApiList // 必填,需要使用的JS接口列表
});

wx.ready(function () {
// 在这里调用 API
configShare();
});

wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期(7200s)等原因触发error函数
console.error('微信JS-SDK配置失败', res);
});
}

// 配置微信分享
function configShare() {
const shareData = {
title: '自定义分享标题', // 分享标题
desc: '自定义分享描述', // 分享描述
link: 'https://example.com', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'https://example.com/path/to/image.jpg', // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户点击了分享后执行的回调函数
console.log('分享成功');
}
};

wx.onMenuShareTimeline(shareData); // 分享到朋友圈
wx.onMenuShareAppMessage(shareData); // 分享给朋友
wx.onMenuShareQQ(shareData); // 分享到QQ
wx.onMenuShareWeibo(shareData); // 分享到微博
}

// 初始化微信JS-SDK
initWechatSDK();

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%