蛋蛋星球-制度模式
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
6.2 KiB

  1. package qq
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "github.com/go-pay/gopay"
  8. "github.com/go-pay/gopay/pkg/xhttp"
  9. )
  10. // 获取开放平台,access_token 返回结构体
  11. type AccessToken struct {
  12. AccessToken string `json:"access_token,omitempty"`
  13. ExpiresIn string `json:"expires_in,omitempty"`
  14. RefreshToken string `json:"refresh_token,omitempty"`
  15. }
  16. // 获取开放平台,access_token 返回结构体
  17. type OpenIdInfo struct {
  18. ClientId string `json:"client_id,omitempty"` // 用户ClientID
  19. OpenId string `json:"openid,omitempty"` // 用户OpenID
  20. UnionId string `json:"unionid,omitempty"` // 用户UnionID
  21. Error int `json:"error,omitempty"` // 错误代码
  22. ErrorDescription string `json:"error_description,omitempty"` // 错误描述
  23. }
  24. // QQ开放平台用户信息
  25. type UserInfo struct {
  26. Ret int `json:"sex,omitempty"` // 返回码
  27. Msg string `json:"msg,omitempty"` // 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。
  28. Nickname string `json:"nickname,omitempty"` // 用户在QQ空间的昵称。
  29. Figureurl string `json:"figureurl,omitempty"` // 大小为30×30像素的QQ空间头像URL。
  30. Figureurl1 string `json:"figureurl_1,omitempty"` // 大小为50×50像素的QQ空间头像URL。
  31. Figureurl2 string `json:"figureurl_2,omitempty"` // 大小为100×100像素的QQ空间头像URL。
  32. FigureurlQq1 string `json:"figureurl_qq_1,omitempty"` // 大小为40×40像素的QQ头像URL。
  33. FigureurlQq2 string `json:"figureurl_qq_2,omitempty"` // 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。
  34. Gender string `json:"gender,omitempty"` // 性别。 如果获取不到则默认返回"男"
  35. IsYellowVip string `json:"is_yellow_vip,omitempty"` // 标识用户是否为黄钻用户(0:不是;1:是)。
  36. Vip string `json:"vip,omitempty"` // 标识用户是否为黄钻用户(0:不是;1:是)
  37. YellowVipLevel string `json:"yellow_vip_level,omitempty"` // 黄钻等级
  38. Level string `json:"level,omitempty"` // 黄钻等级
  39. IsYellowYearVip string `json:"is_yellow_year_vip,omitempty"` // 标识是否为年费黄钻用户(0:不是; 1:是)
  40. }
  41. /*{
  42. "ret":0,
  43. "msg":"",
  44. "nickname":"Peter",
  45. "figureurl":"http://qzapp.qlogo.cn/qzapp/111111/942FEA70050EEAFBD4DCE2C1FC775E56/30",
  46. "figureurl_1":"http://qzapp.qlogo.cn/qzapp/111111/942FEA70050EEAFBD4DCE2C1FC775E56/50",
  47. "figureurl_2":"http://qzapp.qlogo.cn/qzapp/111111/942FEA70050EEAFBD4DCE2C1FC775E56/100",
  48. "figureurl_qq_1":"http://q.qlogo.cn/qqapp/100312990/DE1931D5330620DBD07FB4A5422917B6/40",
  49. "figureurl_qq_2":"http://q.qlogo.cn/qqapp/100312990/DE1931D5330620DBD07FB4A5422917B6/100",
  50. "gender":"男",
  51. "is_yellow_vip":"1",
  52. "vip":"1",
  53. "yellow_vip_level":"7",
  54. "level":"7",
  55. "is_yellow_year_vip":"1"
  56. }*/
  57. // 参数 是否必须 含义
  58. // grant_type 必须 授权类型,在本步骤中,此值为“authorization_code”。
  59. // client_id 必须 申请QQ登录成功后,分配给网站的appid。
  60. // client_secret 必须 申请QQ登录成功后,分配给网站的appkey。
  61. // code 必须 上一步返回的authorization code。
  62. // 如果用户成功登录并授权,则会跳转到指定的回调地址,并在URL中带上Authorization Code。
  63. // 例如,回调地址为www.qq.com/my.php,则跳转到:
  64. // http://www.qq.com/my.php?code=520DD95263C1CFEA087******
  65. // 注意此code会在10分钟内过期。
  66. // redirect_uri 必须 与上面一步中传入的redirect_uri保持一致。
  67. // fmt 可选 因历史原因,默认是x-www-form-urlencoded格式,如果填写json,则返回json格式
  68. // 文档:https://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token#Step2.EF.BC.9A.E9.80.9A.E8.BF.87AuthorizationCode.E8.8E.B7.E5.8F.96AccessToken
  69. func GetAccessToken(ctx context.Context, appId, appSecret, code, redirectUri string) (accessToken *AccessToken, err error) {
  70. accessToken = new(AccessToken)
  71. url := "https://graph.qq.com/oauth2.0/token?client_id=" + appId + "&client_secret=" + appSecret + "&code=" + code + "&redirect_uri=" + redirectUri + "&fmt=json" + "&grant_type=authorization_code"
  72. _, err = xhttp.NewClient().Req().Get(url).EndStruct(ctx, accessToken)
  73. if err != nil {
  74. return nil, err
  75. }
  76. return accessToken, nil
  77. }
  78. // GetOpenId QQ开放平台:使用Access Token来获取用户的OpenID
  79. // accessToken:接口调用凭据
  80. // openId:用户的OpenID
  81. // oauthConsumerKey:AppID
  82. // lang:默认为 zh_CN ,可选填 zh_CN 简体,zh_TW 繁体,en 英语
  83. // 文档:https://wiki.open.qq.com/wiki/website/%E5%BC%80%E5%8F%91%E6%94%BB%E7%95%A5_Server-side#Step2.EF.BC.9A.E8.8E.B7.E5.8F.96Authorization_Code
  84. func GetOpenId(ctx context.Context, accessToken string, lang ...string) (openid *OpenIdInfo, err error) {
  85. openid = new(OpenIdInfo)
  86. url := "https://graph.qq.com/oauth2.0/me?access_token=" + accessToken + "&unionid=1"
  87. if len(lang) == 1 {
  88. url += "&lang=" + lang[0]
  89. }
  90. _, bs, err := xhttp.NewClient().Req().Get(url).EndBytes(ctx)
  91. if err != nil {
  92. return nil, err
  93. }
  94. bs = bytes.ReplaceAll(bs, []byte("callback("), []byte(""))
  95. bs = bytes.ReplaceAll(bs, []byte(");"), []byte(""))
  96. err = json.Unmarshal(bs, openid)
  97. if err != nil {
  98. return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, bs)
  99. }
  100. return
  101. }
  102. // GetUserInfo QQ开放平台:获取用户个人信息
  103. // accessToken:接口调用凭据
  104. // openId:用户的OpenID
  105. // oauthConsumerKey:AppID
  106. // lang:默认为 zh_CN ,可选填 zh_CN 简体,zh_TW 繁体,en 英语
  107. // 文档:https://wiki.open.qq.com/wiki/website/get_user_info
  108. func GetUserInfo(ctx context.Context, accessToken, openId string, oauthConsumerKey string, lang ...string) (userInfo *UserInfo, err error) {
  109. userInfo = new(UserInfo)
  110. url := "https://graph.qq.com/user/get_user_info?access_token=" + accessToken + "&openid=" + openId + "&oauth_consumer_key=" + oauthConsumerKey
  111. if len(lang) == 1 {
  112. url += "&lang=" + lang[0]
  113. }
  114. _, err = xhttp.NewClient().Req().Get(url).EndStruct(ctx, userInfo)
  115. if err != nil {
  116. return nil, err
  117. }
  118. return userInfo, nil
  119. }