access_token.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package context
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "github.com/silenceper/wechat/v2/util"
  8. )
  9. const (
  10. //AccessTokenURL 获取access_token的接口
  11. AccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token"
  12. //CacheKeyPrefix cache前缀
  13. CacheKeyPrefix = "gowechat_miniprogram_"
  14. )
  15. //ResAccessToken struct
  16. type ResAccessToken struct {
  17. util.CommonError
  18. AccessToken string `json:"access_token"`
  19. ExpiresIn int64 `json:"expires_in"`
  20. }
  21. //GetAccessTokenFunc 获取 access token 的函数签名
  22. type GetAccessTokenFunc func(ctx *Context) (accessToken string, err error)
  23. //SetAccessTokenLock 设置读写锁(一个appID一个读写锁)
  24. func (ctx *Context) SetAccessTokenLock(l *sync.RWMutex) {
  25. ctx.accessTokenLock = l
  26. }
  27. //SetGetAccessTokenFunc 设置自定义获取accessToken的方式, 需要自己实现缓存
  28. func (ctx *Context) SetGetAccessTokenFunc(f GetAccessTokenFunc) {
  29. ctx.accessTokenFunc = f
  30. }
  31. //GetAccessToken 获取access_token
  32. func (ctx *Context) GetAccessToken() (accessToken string, err error) {
  33. ctx.accessTokenLock.Lock()
  34. defer ctx.accessTokenLock.Unlock()
  35. if ctx.accessTokenFunc != nil {
  36. return ctx.accessTokenFunc(ctx)
  37. }
  38. accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", CacheKeyPrefix, ctx.AppID)
  39. val := ctx.Cache.Get(accessTokenCacheKey)
  40. if val != nil {
  41. accessToken = val.(string)
  42. return
  43. }
  44. //从微信服务器获取
  45. var resAccessToken ResAccessToken
  46. resAccessToken, err = ctx.GetAccessTokenFromServer()
  47. if err != nil {
  48. return
  49. }
  50. accessToken = resAccessToken.AccessToken
  51. return
  52. }
  53. //GetAccessTokenFromServer 强制从微信服务器获取token
  54. func (ctx *Context) GetAccessTokenFromServer() (resAccessToken ResAccessToken, err error) {
  55. url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", AccessTokenURL, ctx.AppID, ctx.AppSecret)
  56. var body []byte
  57. body, err = util.HTTPGet(url)
  58. if err != nil {
  59. return
  60. }
  61. err = json.Unmarshal(body, &resAccessToken)
  62. if err != nil {
  63. return
  64. }
  65. if resAccessToken.ErrMsg != "" {
  66. err = fmt.Errorf("get access_token error : errcode=%v , errormsg=%v", resAccessToken.ErrCode, resAccessToken.ErrMsg)
  67. return
  68. }
  69. accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", CacheKeyPrefix, ctx.AppID)
  70. expires := resAccessToken.ExpiresIn - 1500
  71. err = ctx.Cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
  72. return
  73. }