accessToken.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package context
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/url"
  6. "time"
  7. "github.com/silenceper/wechat/v2/util"
  8. )
  9. const (
  10. componentAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_component_token"
  11. getPreCodeURL = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=%s"
  12. queryAuthURL = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=%s"
  13. refreshTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=%s"
  14. getComponentInfoURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=%s"
  15. componentLoginURL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%d&biz_appid=%s"
  16. bindComponentURL = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=%d&no_scan=1&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&biz_appid=%s#wechat_redirect"
  17. //TODO 获取授权方选项信息
  18. //getComponentConfigURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token=%s"
  19. //TODO 获取已授权的账号信息
  20. //getuthorizerListURL = "POST https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s"
  21. )
  22. // ComponentAccessToken 第三方平台
  23. type ComponentAccessToken struct {
  24. AccessToken string `json:"component_access_token"`
  25. ExpiresIn int64 `json:"expires_in"`
  26. }
  27. // GetComponentAccessToken 获取 ComponentAccessToken
  28. func (ctx *Context) GetComponentAccessToken() (string, error) {
  29. accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
  30. val := ctx.Cache.Get(accessTokenCacheKey)
  31. if val == nil {
  32. return "", fmt.Errorf("cann't get component access token")
  33. }
  34. return val.(string), nil
  35. }
  36. // SetComponentAccessToken 通过component_verify_ticket 获取 ComponentAccessToken
  37. func (ctx *Context) SetComponentAccessToken(verifyTicket string) (*ComponentAccessToken, error) {
  38. body := map[string]string{
  39. "component_appid": ctx.AppID,
  40. "component_appsecret": ctx.AppSecret,
  41. "component_verify_ticket": verifyTicket,
  42. }
  43. respBody, err := util.PostJSON(componentAccessTokenURL, body)
  44. if err != nil {
  45. return nil, err
  46. }
  47. at := &ComponentAccessToken{}
  48. if err := json.Unmarshal(respBody, at); err != nil {
  49. return nil, err
  50. }
  51. accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
  52. expires := at.ExpiresIn - 1500
  53. if err := ctx.Cache.Set(accessTokenCacheKey, at.AccessToken, time.Duration(expires)*time.Second); err != nil {
  54. return nil, nil
  55. }
  56. return at, nil
  57. }
  58. // GetPreCode 获取预授权码
  59. func (ctx *Context) GetPreCode() (string, error) {
  60. cat, err := ctx.GetComponentAccessToken()
  61. if err != nil {
  62. return "", err
  63. }
  64. req := map[string]string{
  65. "component_appid": ctx.AppID,
  66. }
  67. uri := fmt.Sprintf(getPreCodeURL, cat)
  68. body, err := util.PostJSON(uri, req)
  69. if err != nil {
  70. return "", err
  71. }
  72. var ret struct {
  73. PreCode string `json:"pre_auth_code"`
  74. }
  75. if err := json.Unmarshal(body, &ret); err != nil {
  76. return "", err
  77. }
  78. return ret.PreCode, nil
  79. }
  80. // GetComponentLoginPage 获取第三方公众号授权链接(扫码授权)
  81. func (ctx *Context) GetComponentLoginPage(redirectURI string, authType int, bizAppID string) (string, error) {
  82. code, err := ctx.GetPreCode()
  83. if err != nil {
  84. return "", err
  85. }
  86. return fmt.Sprintf(componentLoginURL, ctx.AppID, code, url.QueryEscape(redirectURI), authType, bizAppID), nil
  87. }
  88. // GetBindComponentURL 获取第三方公众号授权链接(链接跳转,适用移动端)
  89. func (ctx *Context) GetBindComponentURL(redirectURI string, authType int, bizAppID string) (string, error) {
  90. code, err := ctx.GetPreCode()
  91. if err != nil {
  92. return "", err
  93. }
  94. return fmt.Sprintf(bindComponentURL, authType, ctx.AppID, code, url.QueryEscape(redirectURI), bizAppID), nil
  95. }
  96. // ID 微信返回接口中各种类型字段
  97. type ID struct {
  98. ID int `json:"id"`
  99. }
  100. // AuthBaseInfo 授权的基本信息
  101. type AuthBaseInfo struct {
  102. AuthrAccessToken
  103. FuncInfo []AuthFuncInfo `json:"func_info"`
  104. }
  105. // AuthFuncInfo 授权的接口内容
  106. type AuthFuncInfo struct {
  107. FuncscopeCategory ID `json:"funcscope_category"`
  108. }
  109. // AuthrAccessToken 授权方AccessToken
  110. type AuthrAccessToken struct {
  111. Appid string `json:"authorizer_appid"`
  112. AccessToken string `json:"authorizer_access_token"`
  113. ExpiresIn int64 `json:"expires_in"`
  114. RefreshToken string `json:"authorizer_refresh_token"`
  115. }
  116. // QueryAuthCode 使用授权码换取公众号或小程序的接口调用凭据和授权信息
  117. func (ctx *Context) QueryAuthCode(authCode string) (*AuthBaseInfo, error) {
  118. cat, err := ctx.GetComponentAccessToken()
  119. if err != nil {
  120. return nil, err
  121. }
  122. req := map[string]string{
  123. "component_appid": ctx.AppID,
  124. "authorization_code": authCode,
  125. }
  126. uri := fmt.Sprintf(queryAuthURL, cat)
  127. body, err := util.PostJSON(uri, req)
  128. if err != nil {
  129. return nil, err
  130. }
  131. var ret struct {
  132. util.CommonError
  133. Info *AuthBaseInfo `json:"authorization_info"`
  134. }
  135. if err := json.Unmarshal(body, &ret); err != nil {
  136. return nil, err
  137. }
  138. if ret.ErrCode != 0 {
  139. err = fmt.Errorf("QueryAuthCode error : errcode=%v , errmsg=%v", ret.ErrCode, ret.ErrMsg)
  140. return nil, err
  141. }
  142. return ret.Info, nil
  143. }
  144. // RefreshAuthrToken 获取(刷新)授权公众号或小程序的接口调用凭据(令牌)
  145. func (ctx *Context) RefreshAuthrToken(appid, refreshToken string) (*AuthrAccessToken, error) {
  146. cat, err := ctx.GetComponentAccessToken()
  147. if err != nil {
  148. return nil, err
  149. }
  150. req := map[string]string{
  151. "component_appid": ctx.AppID,
  152. "authorizer_appid": appid,
  153. "authorizer_refresh_token": refreshToken,
  154. }
  155. uri := fmt.Sprintf(refreshTokenURL, cat)
  156. body, err := util.PostJSON(uri, req)
  157. if err != nil {
  158. return nil, err
  159. }
  160. ret := &AuthrAccessToken{}
  161. if err := json.Unmarshal(body, ret); err != nil {
  162. return nil, err
  163. }
  164. authrTokenKey := "authorizer_access_token_" + appid
  165. if err := ctx.Cache.Set(authrTokenKey, ret.AccessToken, time.Minute*80); err != nil {
  166. return nil, err
  167. }
  168. return ret, nil
  169. }
  170. // GetAuthrAccessToken 获取授权方AccessToken
  171. func (ctx *Context) GetAuthrAccessToken(appid string) (string, error) {
  172. authrTokenKey := "authorizer_access_token_" + appid
  173. val := ctx.Cache.Get(authrTokenKey)
  174. if val == nil {
  175. return "", fmt.Errorf("cannot get authorizer %s access token", appid)
  176. }
  177. return val.(string), nil
  178. }
  179. // AuthorizerInfo 授权方详细信息
  180. type AuthorizerInfo struct {
  181. NickName string `json:"nick_name"`
  182. HeadImg string `json:"head_img"`
  183. ServiceTypeInfo ID `json:"service_type_info"`
  184. VerifyTypeInfo ID `json:"verify_type_info"`
  185. UserName string `json:"user_name"`
  186. PrincipalName string `json:"principal_name"`
  187. BusinessInfo struct {
  188. OpenStore string `json:"open_store"`
  189. OpenScan string `json:"open_scan"`
  190. OpenPay string `json:"open_pay"`
  191. OpenCard string `json:"open_card"`
  192. OpenShake string `json:"open_shake"`
  193. }
  194. Alias string `json:"alias"`
  195. QrcodeURL string `json:"qrcode_url"`
  196. }
  197. // GetAuthrInfo 获取授权方的帐号基本信息
  198. func (ctx *Context) GetAuthrInfo(appid string) (*AuthorizerInfo, *AuthBaseInfo, error) {
  199. cat, err := ctx.GetComponentAccessToken()
  200. if err != nil {
  201. return nil, nil, err
  202. }
  203. req := map[string]string{
  204. "component_appid": ctx.AppID,
  205. "authorizer_appid": appid,
  206. }
  207. uri := fmt.Sprintf(getComponentInfoURL, cat)
  208. body, err := util.PostJSON(uri, req)
  209. if err != nil {
  210. return nil, nil, err
  211. }
  212. var ret struct {
  213. AuthorizerInfo *AuthorizerInfo `json:"authorizer_info"`
  214. AuthorizationInfo *AuthBaseInfo `json:"authorization_info"`
  215. }
  216. if err := json.Unmarshal(body, &ret); err != nil {
  217. return nil, nil, err
  218. }
  219. return ret.AuthorizerInfo, ret.AuthorizationInfo, nil
  220. }