feat: 公众号登录 共享access_token方案 #3

Merged
wujiefeng merged 3 commits from wfd into master 2025-11-17 11:25:02 +08:00
3 changed files with 94 additions and 7 deletions

23
cache/redis.go vendored Normal file
View File

@ -0,0 +1,23 @@
package cache
import "github.com/go-redis/redis"
var (
redisClient *redis.Client = nil
)
func NewRedis() {
addr := "127.0.0.1:6379"
redis.NewClient(&redis.Options{})
redisClient = redis.NewClient(&redis.Options{
Addr: addr,
})
}
func GetRedis() *redis.Client {
if redisClient == nil {
NewRedis()
}
return redisClient
}

View File

@ -2,11 +2,15 @@ package weixin
import (
"fmt"
"github.com/tidwall/gjson"
"io"
"net/http"
"sync"
"time"
cache2 "git.u8t.cn/open/gosdk/cache"
"github.com/go-redis/redis"
uuid2 "github.com/google/uuid"
"github.com/tidwall/gjson"
)
const (
@ -87,6 +91,65 @@ func (o *BaseSdk) getAccessToken() (string, error) {
return o.accessToken, nil
}
// redis share version
func (o *BaseSdk) getAccessToken2() (string, error) {
redix := o.getRedis()
tokenKey := fmt.Sprintf("weixin_oa_access_token_v2_%s", o.appid)
lockKey := fmt.Sprintf("get_access_token_unique_%s", o.appid)
uuid := uuid2.New().String()
// get token
token := redix.Get(tokenKey).Val()
if token != "" {
return token, nil
}
// setEX and expire
// if not set key. wait 200ms and get again and retry 5 times
if ok := redix.SetNX(lockKey, uuid, 10*time.Second).Val(); !ok {
for i := range 5 {
time.Sleep(time.Duration(200*(i+2)) * time.Millisecond)
if token = redix.Get(tokenKey).Val(); token != "" {
return token, nil
}
}
return "", fmt.Errorf("<get access_token v2> wait 5 times,but still not get token")
}
defer func() {
if redix.Get(lockKey).Val() == uuid {
redix.Del(lockKey)
}
}()
// get new token
url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", accessTokenUrl, o.appid, o.secret)
res, err := http.Get(url)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
g := gjson.ParseBytes(body)
token = g.Get("access_token").String()
if token == "" {
return "", fmt.Errorf("%d:%s", g.Get("errcode").Int(), g.Get("errmsg").String())
}
expire := g.Get("expires_in").Int() - 10
redix.Set(tokenKey, token, time.Second*time.Duration(expire))
return token, nil
}
func (o *BaseSdk) getRedis() *redis.Client {
return cache2.GetRedis()
}
func (o *BaseSdk) getUserInfoByCode(code string, auth bool) (*UserInfo, error) {
url := fmt.Sprintf("%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
code2AccessTokenUrl, o.appid, o.secret, code)

View File

@ -4,11 +4,12 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/tidwall/gjson"
"io"
"mime/multipart"
"net/http"
"time"
"github.com/tidwall/gjson"
)
type OaSdk struct {
@ -35,7 +36,7 @@ func (o *OaSdk) GetQrCode(sceneStr string) (string, error) {
}
marshal, _ := json.Marshal(params)
accessToken, err := o.getAccessToken()
accessToken, err := o.getAccessToken2()
if err != nil {
return "", err
}
@ -68,7 +69,7 @@ func (o *OaSdk) GetUserInfoByCodeNoAuth(code string) (*UserInfo, error) {
}
func (o *OaSdk) GetUserInfoByOpenid(openid string) (*UserInfo, error) {
accessToken, err := o.getAccessToken()
accessToken, err := o.getAccessToken2()
if err != nil {
return nil, err
}
@ -115,7 +116,7 @@ func (o *OaSdk) UploadFileByByte(file []byte, ext string) (string, string, error
if err != nil {
return "", "", err
}
token, err := o.getAccessToken()
token, err := o.getAccessToken2()
if err != nil {
return "", "", err
}
@ -155,7 +156,7 @@ func (o *OaSdk) UploadFileByByte(file []byte, ext string) (string, string, error
}
func (o *OaSdk) CreateMenu(buttons []*OaMenuButton) error {
accessToken, err := o.getAccessToken()
accessToken, err := o.getAccessToken2()
if err != nil {
return err
}
@ -182,7 +183,7 @@ func (o *OaSdk) CreateMenu(buttons []*OaMenuButton) error {
}
func (o *OaSdk) DeleteMenu() error {
accessToken, err := o.getAccessToken()
accessToken, err := o.getAccessToken2()
if err != nil {
return err
}