mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-13 17:22:26 +08:00
Compare commits
3 Commits
v2.1.8
...
1496cb1574
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1496cb1574 | ||
|
|
dd5f680161 | ||
|
|
988ea49a03 |
@@ -7,16 +7,6 @@ type AccessTokenHandle interface {
|
|||||||
GetAccessToken() (accessToken string, err error)
|
GetAccessToken() (accessToken string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessTokenCompatibleHandle 同时实现 AccessTokenHandle 和 AccessTokenContextHandle
|
|
||||||
type AccessTokenCompatibleHandle struct {
|
|
||||||
AccessTokenHandle
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccessTokenContext 获取access_token,先从cache中获取,没有则从服务端获取
|
|
||||||
func (c AccessTokenCompatibleHandle) GetAccessTokenContext(_ context.Context) (accessToken string, err error) {
|
|
||||||
return c.GetAccessToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccessTokenContextHandle AccessToken 接口
|
// AccessTokenContextHandle AccessToken 接口
|
||||||
type AccessTokenContextHandle interface {
|
type AccessTokenContextHandle interface {
|
||||||
AccessTokenHandle
|
AccessTokenHandle
|
||||||
|
|||||||
@@ -195,21 +195,15 @@ type WorkAccessToken struct {
|
|||||||
accessTokenLock *sync.Mutex
|
accessTokenLock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWorkAccessToken new WorkAccessToken (保持向后兼容)
|
// NewWorkAccessToken new WorkAccessToken
|
||||||
func NewWorkAccessToken(corpID, corpSecret, agentID, cacheKeyPrefix string, cache cache.Cache) AccessTokenContextHandle {
|
func NewWorkAccessToken(corpID, corpSecret, agentID, cacheKeyPrefix string, cache cache.Cache) AccessTokenContextHandle {
|
||||||
// 调用新方法,保持兼容性
|
|
||||||
return NewWorkAccessTokenWithAgentID(corpID, corpSecret, agentID, cacheKeyPrefix, cache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWorkAccessTokenWithAgentID new WorkAccessToken with agentID
|
|
||||||
func NewWorkAccessTokenWithAgentID(corpID, corpSecret, agentID, cacheKeyPrefix string, cache cache.Cache) AccessTokenContextHandle {
|
|
||||||
if cache == nil {
|
if cache == nil {
|
||||||
panic("cache is needed")
|
panic("cache the not exist")
|
||||||
}
|
}
|
||||||
return &WorkAccessToken{
|
return &WorkAccessToken{
|
||||||
CorpID: corpID,
|
CorpID: corpID,
|
||||||
CorpSecret: corpSecret,
|
CorpSecret: corpSecret,
|
||||||
AgentID: agentID,
|
AgentID: agentID, // agentID可以为空,兼容历史版本
|
||||||
cache: cache,
|
cache: cache,
|
||||||
cacheKeyPrefix: cacheKeyPrefix,
|
cacheKeyPrefix: cacheKeyPrefix,
|
||||||
accessTokenLock: new(sync.Mutex),
|
accessTokenLock: new(sync.Mutex),
|
||||||
@@ -229,7 +223,8 @@ func (ak *WorkAccessToken) GetAccessTokenContext(ctx context.Context) (accessTok
|
|||||||
|
|
||||||
// 构建缓存key
|
// 构建缓存key
|
||||||
var accessTokenCacheKey string
|
var accessTokenCacheKey string
|
||||||
|
// 每个应用有独立的secret,获取到的access_token只能本应用使用,所以每个应用的access_token应该分开来获取
|
||||||
|
// API文档:https://developer.work.weixin.qq.com/document/path/91039
|
||||||
if ak.AgentID != "" {
|
if ak.AgentID != "" {
|
||||||
// 如果设置了AgentID,使用新的key格式
|
// 如果设置了AgentID,使用新的key格式
|
||||||
accessTokenCacheKey = fmt.Sprintf("%s_access_token_%s_%s", ak.cacheKeyPrefix, ak.CorpID, ak.AgentID)
|
accessTokenCacheKey = fmt.Sprintf("%s_access_token_%s_%s", ak.cacheKeyPrefix, ak.CorpID, ak.AgentID)
|
||||||
@@ -253,9 +248,6 @@ func (ak *WorkAccessToken) GetAccessTokenContext(ctx context.Context) (accessTok
|
|||||||
|
|
||||||
expires := resAccessToken.ExpiresIn - 1500
|
expires := resAccessToken.ExpiresIn - 1500
|
||||||
err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
accessToken = resAccessToken.AccessToken
|
accessToken = resAccessToken.AccessToken
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
package credential
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/cache"
|
|
||||||
"github.com/silenceper/wechat/v2/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TicketType ticket类型
|
|
||||||
type TicketType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TicketTypeCorpJs 企业jsapi ticket
|
|
||||||
TicketTypeCorpJs TicketType = iota
|
|
||||||
// TicketTypeAgentJs 应用jsapi ticket
|
|
||||||
TicketTypeAgentJs
|
|
||||||
)
|
|
||||||
|
|
||||||
// 企业微信相关的 ticket URL
|
|
||||||
const (
|
|
||||||
// 企业微信 jsapi ticket
|
|
||||||
getWorkJsTicketURL = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=%s"
|
|
||||||
// 企业微信应用 jsapi ticket
|
|
||||||
getWorkAgentJsTicketURL = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=%s&type=agent_config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WorkJsTicket 企业微信js ticket获取
|
|
||||||
type WorkJsTicket struct {
|
|
||||||
corpID string
|
|
||||||
agentID string
|
|
||||||
cacheKeyPrefix string
|
|
||||||
cache cache.Cache
|
|
||||||
jsAPITicketLock *sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWorkJsTicket new WorkJsTicket
|
|
||||||
func NewWorkJsTicket(corpID, agentID, cacheKeyPrefix string, cache cache.Cache) *WorkJsTicket {
|
|
||||||
return &WorkJsTicket{
|
|
||||||
corpID: corpID,
|
|
||||||
agentID: agentID,
|
|
||||||
cache: cache,
|
|
||||||
cacheKeyPrefix: cacheKeyPrefix,
|
|
||||||
jsAPITicketLock: new(sync.Mutex),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTicket 根据类型获取相应的jsapi_ticket
|
|
||||||
func (js *WorkJsTicket) GetTicket(accessToken string, ticketType TicketType) (ticketStr string, err error) {
|
|
||||||
var cacheKey string
|
|
||||||
switch ticketType {
|
|
||||||
case TicketTypeCorpJs:
|
|
||||||
cacheKey = fmt.Sprintf("%s_corp_jsapi_ticket_%s", js.cacheKeyPrefix, js.corpID)
|
|
||||||
case TicketTypeAgentJs:
|
|
||||||
if js.agentID == "" {
|
|
||||||
err = fmt.Errorf("agentID is empty")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cacheKey = fmt.Sprintf("%s_agent_jsapi_ticket_%s_%s", js.cacheKeyPrefix, js.corpID, js.agentID)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unsupported ticket type: %v", ticketType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if val := js.cache.Get(cacheKey); val != nil {
|
|
||||||
return val.(string), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
js.jsAPITicketLock.Lock()
|
|
||||||
defer js.jsAPITicketLock.Unlock()
|
|
||||||
|
|
||||||
// 双检,防止重复从微信服务器获取
|
|
||||||
if val := js.cache.Get(cacheKey); val != nil {
|
|
||||||
return val.(string), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var ticket ResTicket
|
|
||||||
ticket, err = js.getTicketFromServer(accessToken, ticketType)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
expires := ticket.ExpiresIn - 1500
|
|
||||||
err = js.cache.Set(cacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
|
|
||||||
ticketStr = ticket.Ticket
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTicketFromServer 从服务器中获取ticket
|
|
||||||
func (js *WorkJsTicket) getTicketFromServer(accessToken string, ticketType TicketType) (ticket ResTicket, err error) {
|
|
||||||
var url string
|
|
||||||
switch ticketType {
|
|
||||||
case TicketTypeCorpJs:
|
|
||||||
url = fmt.Sprintf(getWorkJsTicketURL, accessToken)
|
|
||||||
case TicketTypeAgentJs:
|
|
||||||
url = fmt.Sprintf(getWorkAgentJsTicketURL, accessToken)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unsupported ticket type: %v", ticketType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var response []byte
|
|
||||||
response, err = util.HTTPGet(url)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(response, &ticket)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ticket.ErrCode != 0 {
|
|
||||||
err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", ticket.ErrCode, ticket.ErrMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -34,7 +34,7 @@ func (business *Business) GetPhoneNumber(in *GetPhoneNumberRequest) (info PhoneI
|
|||||||
|
|
||||||
// GetPhoneNumberWithContext 利用context将code换取用户手机号。 每个code只能使用一次,code的有效期为5min
|
// GetPhoneNumberWithContext 利用context将code换取用户手机号。 每个code只能使用一次,code的有效期为5min
|
||||||
func (business *Business) GetPhoneNumberWithContext(ctx context.Context, in *GetPhoneNumberRequest) (info PhoneInfo, err error) {
|
func (business *Business) GetPhoneNumberWithContext(ctx context.Context, in *GetPhoneNumberRequest) (info PhoneInfo, err error) {
|
||||||
accessToken, err := business.GetAccessTokenContext(ctx)
|
accessToken, err := business.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ import (
|
|||||||
// Context struct
|
// Context struct
|
||||||
type Context struct {
|
type Context struct {
|
||||||
*config.Config
|
*config.Config
|
||||||
credential.AccessTokenContextHandle
|
credential.AccessTokenHandle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,22 +42,15 @@ func NewMiniProgram(cfg *config.Config) *MiniProgram {
|
|||||||
defaultAkHandle = credential.NewDefaultAccessToken(cfg.AppID, cfg.AppSecret, cacheKeyPrefix, cfg.Cache)
|
defaultAkHandle = credential.NewDefaultAccessToken(cfg.AppID, cfg.AppSecret, cacheKeyPrefix, cfg.Cache)
|
||||||
}
|
}
|
||||||
ctx := &context.Context{
|
ctx := &context.Context{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
AccessTokenContextHandle: defaultAkHandle,
|
AccessTokenHandle: defaultAkHandle,
|
||||||
}
|
}
|
||||||
return &MiniProgram{ctx}
|
return &MiniProgram{ctx}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAccessTokenHandle 自定义 access_token 获取方式
|
// SetAccessTokenHandle 自定义 access_token 获取方式
|
||||||
func (miniProgram *MiniProgram) SetAccessTokenHandle(accessTokenHandle credential.AccessTokenHandle) {
|
func (miniProgram *MiniProgram) SetAccessTokenHandle(accessTokenHandle credential.AccessTokenHandle) {
|
||||||
miniProgram.ctx.AccessTokenContextHandle = credential.AccessTokenCompatibleHandle{
|
miniProgram.ctx.AccessTokenHandle = accessTokenHandle
|
||||||
AccessTokenHandle: accessTokenHandle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAccessTokenContextHandle 自定义 access_token 获取方式
|
|
||||||
func (miniProgram *MiniProgram) SetAccessTokenContextHandle(accessTokenContextHandle credential.AccessTokenContextHandle) {
|
|
||||||
miniProgram.ctx.AccessTokenContextHandle = accessTokenContextHandle
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContext get Context
|
// GetContext get Context
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func (js *Js) SetJsTicketHandle(ticketHandle credential.JsTicketHandle) {
|
|||||||
// GetConfig 获取jssdk需要的配置参数
|
// GetConfig 获取jssdk需要的配置参数
|
||||||
// uri 为当前网页地址
|
// uri 为当前网页地址
|
||||||
func (js *Js) GetConfig(uri string) (config *Config, err error) {
|
func (js *Js) GetConfig(uri string) (config *Config, err error) {
|
||||||
|
config = new(Config)
|
||||||
var accessToken string
|
var accessToken string
|
||||||
accessToken, err = js.GetAccessToken()
|
accessToken, err = js.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,11 +50,12 @@ func (js *Js) GetConfig(uri string) (config *Config, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nonceStr := util.RandomStr(16)
|
nonceStr := util.RandomStr(16)
|
||||||
timestamp := util.GetCurrTS()
|
timestamp := util.GetCurrTS()
|
||||||
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", ticketStr, nonceStr, timestamp, uri)
|
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", ticketStr, nonceStr, timestamp, uri)
|
||||||
sigStr := util.Signature(str)
|
sigStr := util.Signature(str)
|
||||||
config = new(Config)
|
|
||||||
config.AppID = js.AppID
|
config.AppID = js.AppID
|
||||||
config.NonceStr = nonceStr
|
config.NonceStr = nonceStr
|
||||||
config.Timestamp = timestamp
|
config.Timestamp = timestamp
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package miniprogram
|
package miniprogram
|
||||||
|
|
||||||
import (
|
import (
|
||||||
originalContext "context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/credential"
|
"github.com/silenceper/wechat/v2/credential"
|
||||||
@@ -38,22 +37,6 @@ func (miniProgram *MiniProgram) GetAccessToken() (string, error) {
|
|||||||
return akRes.AccessToken, nil
|
return akRes.AccessToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccessTokenContext 利用ctx获取ak
|
|
||||||
func (miniProgram *MiniProgram) GetAccessTokenContext(ctx originalContext.Context) (string, error) {
|
|
||||||
ak, akErr := miniProgram.openContext.GetAuthrAccessTokenContext(ctx, miniProgram.AppID)
|
|
||||||
if akErr == nil {
|
|
||||||
return ak, nil
|
|
||||||
}
|
|
||||||
if miniProgram.authorizerRefreshToken == "" {
|
|
||||||
return "", fmt.Errorf("please set the authorizer_refresh_token first")
|
|
||||||
}
|
|
||||||
akRes, akResErr := miniProgram.GetComponent().RefreshAuthrTokenContext(ctx, miniProgram.AppID, miniProgram.authorizerRefreshToken)
|
|
||||||
if akResErr != nil {
|
|
||||||
return "", akResErr
|
|
||||||
}
|
|
||||||
return akRes.AccessToken, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAuthorizerRefreshToken 设置代执操作业务授权账号authorizer_refresh_token
|
// SetAuthorizerRefreshToken 设置代执操作业务授权账号authorizer_refresh_token
|
||||||
func (miniProgram *MiniProgram) SetAuthorizerRefreshToken(authorizerRefreshToken string) *MiniProgram {
|
func (miniProgram *MiniProgram) SetAuthorizerRefreshToken(authorizerRefreshToken string) *MiniProgram {
|
||||||
miniProgram.authorizerRefreshToken = authorizerRefreshToken
|
miniProgram.authorizerRefreshToken = authorizerRefreshToken
|
||||||
@@ -85,7 +68,7 @@ func (miniProgram *MiniProgram) GetBasic() *basic.Basic {
|
|||||||
// GetURLLink 小程序URL Link接口 调用前需确认已调用 SetAuthorizerRefreshToken 避免由于缓存中 authorizer_access_token 过期执行中断
|
// GetURLLink 小程序URL Link接口 调用前需确认已调用 SetAuthorizerRefreshToken 避免由于缓存中 authorizer_access_token 过期执行中断
|
||||||
func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink {
|
func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink {
|
||||||
return urllink.NewURLLink(&miniContext.Context{
|
return urllink.NewURLLink(&miniContext.Context{
|
||||||
AccessTokenContextHandle: miniProgram,
|
AccessTokenHandle: miniProgram,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ import (
|
|||||||
|
|
||||||
// Config for 企业微信
|
// Config for 企业微信
|
||||||
type Config struct {
|
type Config struct {
|
||||||
CorpID string `json:"corp_id"` // corp_id
|
CorpID string `json:"corp_id"` // corp_id
|
||||||
CorpSecret string `json:"corp_secret"` // corp_secret,如果需要获取会话存档实例,当前参数请填写聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看
|
CorpSecret string `json:"corp_secret"` // corp_secret,如果需要获取会话存档实例,当前参数请填写聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看
|
||||||
AgentID string `json:"agent_id"` // agent_id
|
AgentID string `json:"agent_id"` // agent_id
|
||||||
Cache cache.Cache
|
Cache cache.Cache
|
||||||
RasPrivateKey string // 消息加密私钥,可以在企业微信管理端--管理工具--消息加密公钥查看对用公钥,私钥一般由自己保存
|
RasPrivateKey string // 消息加密私钥,可以在企业微信管理端--管理工具--消息加密公钥查看对用公钥,私钥一般由自己保存
|
||||||
|
|
||||||
Token string `json:"token"` // 微信客服回调配置,用于生成签名校验回调请求的合法性
|
Token string `json:"token"` // 微信客服回调配置,用于生成签名校验回调请求的合法性
|
||||||
EncodingAESKey string `json:"encoding_aes_key"` // 微信客服回调p配置,用于解密回调消息内容对应的密文
|
EncodingAESKey string `json:"encoding_aes_key"` // 微信客服回调p配置,用于解密回调消息内容对应的密文
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
package jsapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/credential"
|
|
||||||
"github.com/silenceper/wechat/v2/util"
|
|
||||||
"github.com/silenceper/wechat/v2/work/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Js struct
|
|
||||||
type Js struct {
|
|
||||||
*context.Context
|
|
||||||
jsTicket *credential.WorkJsTicket
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewJs init
|
|
||||||
func NewJs(context *context.Context) *Js {
|
|
||||||
js := new(Js)
|
|
||||||
js.Context = context
|
|
||||||
js.jsTicket = credential.NewWorkJsTicket(
|
|
||||||
context.Config.CorpID,
|
|
||||||
context.Config.AgentID,
|
|
||||||
credential.CacheKeyWorkPrefix,
|
|
||||||
context.Cache,
|
|
||||||
)
|
|
||||||
return js
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config 返回给用户使用的配置
|
|
||||||
type Config struct {
|
|
||||||
Timestamp int64 `json:"timestamp"`
|
|
||||||
NonceStr string `json:"nonce_str"`
|
|
||||||
Signature string `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetConfig 获取企业微信JS配置 https://developer.work.weixin.qq.com/document/path/90514
|
|
||||||
func (js *Js) GetConfig(uri string) (config *Config, err error) {
|
|
||||||
config = new(Config)
|
|
||||||
var accessToken string
|
|
||||||
accessToken, err = js.GetAccessToken()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var ticketStr string
|
|
||||||
ticketStr, err = js.jsTicket.GetTicket(accessToken, credential.TicketTypeCorpJs)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
config.NonceStr = util.RandomStr(16)
|
|
||||||
config.Timestamp = util.GetCurrTS()
|
|
||||||
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", ticketStr, config.NonceStr, config.Timestamp, uri)
|
|
||||||
config.Signature = util.Signature(str)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAgentConfig 获取企业微信应用JS配置 https://developer.work.weixin.qq.com/document/path/94313
|
|
||||||
func (js *Js) GetAgentConfig(uri string) (config *Config, err error) {
|
|
||||||
config = new(Config)
|
|
||||||
var accessToken string
|
|
||||||
accessToken, err = js.GetAccessToken()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var ticketStr string
|
|
||||||
ticketStr, err = js.jsTicket.GetTicket(accessToken, credential.TicketTypeAgentJs)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
config.NonceStr = util.RandomStr(16)
|
|
||||||
config.Timestamp = util.GetCurrTS()
|
|
||||||
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", ticketStr, config.NonceStr, config.Timestamp, uri)
|
|
||||||
config.Signature = util.Signature(str)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/silenceper/wechat/v2/work/context"
|
"github.com/silenceper/wechat/v2/work/context"
|
||||||
"github.com/silenceper/wechat/v2/work/externalcontact"
|
"github.com/silenceper/wechat/v2/work/externalcontact"
|
||||||
"github.com/silenceper/wechat/v2/work/invoice"
|
"github.com/silenceper/wechat/v2/work/invoice"
|
||||||
"github.com/silenceper/wechat/v2/work/jsapi"
|
|
||||||
"github.com/silenceper/wechat/v2/work/kf"
|
"github.com/silenceper/wechat/v2/work/kf"
|
||||||
"github.com/silenceper/wechat/v2/work/material"
|
"github.com/silenceper/wechat/v2/work/material"
|
||||||
"github.com/silenceper/wechat/v2/work/message"
|
"github.com/silenceper/wechat/v2/work/message"
|
||||||
@@ -53,11 +52,6 @@ func (wk *Work) GetKF() (*kf.Client, error) {
|
|||||||
return kf.NewClient(wk.ctx.Config)
|
return kf.NewClient(wk.ctx.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JsSdk get JsSdk
|
|
||||||
func (wk *Work) JsSdk() *jsapi.Js {
|
|
||||||
return jsapi.NewJs(wk.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExternalContact get external_contact
|
// GetExternalContact get external_contact
|
||||||
func (wk *Work) GetExternalContact() *externalcontact.Client {
|
func (wk *Work) GetExternalContact() *externalcontact.Client {
|
||||||
return externalcontact.NewClient(wk.ctx)
|
return externalcontact.NewClient(wk.ctx)
|
||||||
|
|||||||
Reference in New Issue
Block a user