Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:新增JS-SDK使用权限签名 #796

Open
wants to merge 32 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7e24cb9
完善企业微信API
Oct 28, 2021
829356e
fork github.com/hb1707/wechat/v2
Oct 28, 2021
af5115f
fork github.com/silenceper/wechat/v2
Oct 28, 2021
73adb7d
删除冗余代码
Oct 28, 2021
7ae8e08
企业微信内部开发API:消息推送与接收,以及回调处理
Nov 24, 2021
5704abb
企业微信内部开发API:新增获取客户列表,客户详情,并群发消息
Nov 29, 2021
1f80c26
企业微信内部开发API:新增jssdk支持和Oauth用户身份验证
Jan 26, 2022
88f07bc
企业微信内部开发API:新增jssdk支持
Jan 26, 2022
6313e3d
企业微信内部开发API:完善企业内部消息推送
Mar 2, 2022
96e7945
企业微信内部开发API:消息推送》接收消息与事件》事件格式》模板卡片事件推送
Mar 17, 2022
586a3b0
企业微信内部开发API:消息推送》接收消息与事件》事件格式》模板卡片事件推送
Mar 24, 2022
502a781
企业微信内部开发API:客户联系》编辑客户企业标签
Jan 9, 2023
da20182
企业微信内部开发API:忽略掉一些可能不需要的字段
Jan 9, 2023
cec8177
企业微信内部开发API:增加README.md
Jan 9, 2023
b440267
Merge branch 'release-2.0' of github.com:hb1707/wechat into release-2.0
Jan 9, 2023
1cd6133
与origin代码同步
Jan 9, 2023
589de19
与origin代码同步
Jan 9, 2023
e351d0b
与origin代码同步
Jan 9, 2023
158fbca
新增模板卡片消息
Feb 15, 2023
1c23607
Merge remote-tracking branch 'origin/release-2.0' into release-2.0
Apr 12, 2024
06c225c
Merge remote-tracking branch '官方/v2' into release-2.0
May 13, 2024
4a4339f
补丁
Sep 27, 2024
61bcd6b
feat:新增JS-SDK使用权限签名
Sep 27, 2024
bcdb2fa
feat:新增企业微信消息推送接收和发送
Sep 27, 2024
a7347f9
Merge pull request #1 from hb1707/v2-hb
hb1707 Nov 15, 2024
8a044dc
自用分支
Nov 15, 2024
06e92dd
Merge remote-tracking branch 'origin/release-2.0-hb' into release-2.0-hb
Nov 15, 2024
0f3c9cd
还原
Nov 15, 2024
961d560
Merge pull request #2 from hb1707/release-2.0-hb
hb1707 Nov 15, 2024
d28c61a
Merge branch 'silenceper:v2' into v2
hb1707 Nov 15, 2024
d08b189
Merge pull request #3 from hb1707/v2
hb1707 Nov 15, 2024
0e7907e
Merge pull request #4 from hb1707/v2-hb
hb1707 Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions credential/work_js_ticket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package credential

import (
"encoding/json"
"fmt"
"sync"
"time"

"github.com/silenceper/wechat/v2/cache"
"github.com/silenceper/wechat/v2/util"
)

//获取ticket的url https://developer.work.weixin.qq.com/document/path/90506

Check failure on line 13 in credential/work_js_ticket.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.16)

File is not `gofmt`-ed with `-s` (gofmt)
const getQyWxTicketURL = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=%s"
const getQyAppTicketURL = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=%s&type=agent_config"

//WorkJsTicket 默认获取js ticket方法
type WorkJsTicket struct {
appID string
agentID string
cacheKeyPrefix string
cache cache.Cache
//jsAPITicket 读写锁 同一个AppID一个
jsAPITicketLock *sync.Mutex
}

//NewWorkJsTicket new
func NewWorkJsTicket(appID string, agentID string, cacheKeyPrefix string, cache cache.Cache) JsTicketHandle {
return &WorkJsTicket{
appID: appID,
agentID: agentID,
cache: cache,
cacheKeyPrefix: cacheKeyPrefix,
jsAPITicketLock: new(sync.Mutex),
}
}

//GetTicket 获取企业微信jsapi_ticket
func (js *WorkJsTicket) GetTicket(accessToken string) (ticketStr string, err error) {
//先从cache中取
jsAPITicketCacheKey := fmt.Sprintf("%s_jsapi_ticket_%s", js.cacheKeyPrefix, js.appID)
if val := js.cache.Get(jsAPITicketCacheKey); val != nil {
return val.(string), nil
}

js.jsAPITicketLock.Lock()
defer js.jsAPITicketLock.Unlock()

// 双检,防止重复从微信服务器获取
if val := js.cache.Get(jsAPITicketCacheKey); val != nil {
return val.(string), nil
}

var ticket ResTicket
ticket, err = GetQyWxTicketFromServer(accessToken, js.agentID != "")
if err != nil {
return
}
expires := ticket.ExpiresIn - 1500
err = js.cache.Set(jsAPITicketCacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
ticketStr = ticket.Ticket
return
}

//GetQyWxTicketFromServer 从企业微信服务器中获取ticket
func GetQyWxTicketFromServer(accessToken string, isApp bool) (ticket ResTicket, err error) {
var response []byte
url := fmt.Sprintf(getQyWxTicketURL, accessToken)
if isApp {
url = fmt.Sprintf(getQyAppTicketURL, accessToken)
}
response, err = util.HTTPGet(url)
houseme marked this conversation as resolved.
Show resolved Hide resolved
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
}
16 changes: 13 additions & 3 deletions miniprogram/encryptor/encryptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"encoding/json"
"errors"
"fmt"

"github.com/silenceper/wechat/v2/miniprogram/context"

Check failure on line 10 in miniprogram/encryptor/encryptor.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.16)

File is not `goimports`-ed (goimports)
"strings"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里strings应该紧跟在fmt 后面,以及第10行的空格不要删除

)

// Encryptor struct
Expand Down Expand Up @@ -108,13 +108,23 @@
}

// Decrypt 解密数据
func (encryptor *Encryptor) Decrypt(sessionKey, encryptedData, iv string) (*PlainData, error) {
func (encryptor *Encryptor) Decrypt(sessionKey, encryptedData, appid string) (*PlainData, error) {
ivB := make([]byte, 16)
iv := base64.StdEncoding.EncodeToString(ivB)
cipherText, err := GetCipherText(sessionKey, encryptedData, iv)
if err != nil {
return nil, err
}
length := string(cipherText[:20])

cipherTextData := strings.TrimPrefix(string(cipherText), string(cipherText[:20]))
cipherTextData = strings.TrimSuffix(cipherTextData, appid)

if len(length) != len(cipherTextData) {
return nil, fmt.Errorf("length not match, %d != %d", length, len(cipherTextData))
}
var plainData PlainData
err = json.Unmarshal(cipherText, &plainData)
err = json.Unmarshal([]byte(cipherTextData), &plainData)
if err != nil {
return nil, err
}
Expand Down
14 changes: 14 additions & 0 deletions util/signature.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package util

import (
"bytes"
"crypto/sha1"
"fmt"
"io"
Expand All @@ -16,3 +17,16 @@
}
return fmt.Sprintf("%x", h.Sum(nil))
}

func CalSignature(params ...string) string {

Check failure on line 21 in util/signature.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.16)

exported function `CalSignature` should have comment or be unexported (golint)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

公共方法需要有注释说明

sort.Strings(params)
var buffer bytes.Buffer
for _, value := range params {
buffer.WriteString(value)
}

sha := sha1.New()
sha.Write(buffer.Bytes())
signature := fmt.Sprintf("%x", sha.Sum(nil))
return string(signature)
}
90 changes: 90 additions & 0 deletions work/externalcontact/add_msg_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package externalcontact

import (
"encoding/json"
"fmt"

Check failure on line 5 in work/externalcontact/add_msg_template.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.16)

File is not `goimports`-ed (goimports)
"github.com/silenceper/wechat/v2/util"
Copy link
Collaborator

@houseme houseme Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import是按组引入,比如系统包一组,第三方一组,自己的一组,中间用空行分隔

)

const (
addMsgTemplateUrl = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template"
)

type ChatType string

const (
ChatTypeSingle ChatType = "single"
ChatTypeGroup ChatType = "group"
)

// ReqMessage 企业群发参数
type ReqMessage struct {
ChatType ChatType `json:"chat_type"` //群发任务的类型,默认为single,表示发送给客户,group表示发送给客户群
ExternalUserid []string `json:"external_userid"` // 客户的外部联系人id列表,仅在chat_type为single时有效,不可与sender同时为空,最多可传入1万个客户
Sender string `json:"sender"` //发送企业群发消息的成员userid,当类型为发送给客户群时必填
Text struct {
Content string `json:"content"`
} `json:"text"`
Attachments []struct {
Msgtype string `json:"msgtype"`
Image MsgImage `json:"image"`
Link MsgLink `json:"link"`
Miniprogram MsgMiniprogram `json:"miniprogram"`
Video MsgVideo `json:"video"`
File MsgFile `json:"file"`
} `json:"attachments"`
}
type MsgImage struct {
MediaId string `json:"media_id"`
PicUrl string `json:"pic_url"`
}
type MsgLink struct {
Title string `json:"title"`
Picurl string `json:"picurl"`
Desc string `json:"desc"`
Url string `json:"url"`
}
type MsgMiniprogram struct {
Title string `json:"title"`
PicMediaId string `json:"pic_media_id"`
Appid string `json:"appid"`
Page string `json:"page"`
}
type MsgVideo struct {
MediaId string `json:"media_id"`
}
type MsgFile struct {
MediaId string `json:"media_id"`
}

type resTemplateSend struct {
util.CommonError
FailList string `json:"fail_list"`
MsgID int64 `json:"msgid"`
}

// Send 发送应用消息
func (r *Client) Send(msg *ReqMessage) (msgID int64, err error) {
var accessToken string
accessToken, err = r.GetAccessToken()
if err != nil {
return
}
uri := fmt.Sprintf("%s?access_token=%s", addMsgTemplateUrl, accessToken)
var response []byte
response, err = util.PostJSON(uri, msg)
if err != nil {
return
}
var result resTemplateSend
err = json.Unmarshal(response, &result)
if err != nil {
return
}
if result.ErrCode != 0 {
err = fmt.Errorf("template msg send error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
return
}
msgID = result.MsgID
return
}
Loading
Loading