ex_auth.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package exchange
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/demdxx/gocast"
  6. "strings"
  7. "time"
  8. )
  9. // doc: https://dsgxajqzhgq3.sg.larksuite.com/wiki/Xxp0wsLKmiZFB3kRqJYl3cqlgHb
  10. // 平台授权链接
  11. // 正式环境跳转地址为配置项目 为兼容测试环境/web环境 当无法获得指定跳转地址则使用默认root_url
  12. // root_url
  13. func AuthRoot() string {
  14. return conf().RootUrl
  15. }
  16. // 测试环境使用
  17. func AuthUrl(redirectUri string, args ...string) string {
  18. uri := AuthUri(redirectUri, args...)
  19. return ToPath(conf().RootUrl, uri)
  20. }
  21. func NoDomainAuthUrl(redirectUri string, args ...string) string {
  22. realRedirect := conf().RedirectUrl
  23. if redirectUri != "" {
  24. realRedirect = redirectUri
  25. }
  26. // 自动跳转 scope=snsapi_base
  27. //uri := fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s", conf().Appid, realRedirect)
  28. uri := fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s", conf().Appid, realRedirect)
  29. if len(args) > 0 {
  30. //uri = fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, ""))
  31. uri = fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, ""))
  32. }
  33. return uri
  34. }
  35. // uri
  36. func AuthUri(redirectUri string, args ...string) string {
  37. realRedirect := conf().RedirectUrl
  38. if redirectUri != "" {
  39. realRedirect = redirectUri
  40. }
  41. // 自动跳转 scope=snsapi_base
  42. //uri := fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s", conf().Appid, realRedirect)
  43. uri := fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s", conf().Appid, realRedirect)
  44. if len(args) > 0 {
  45. //uri = fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, ""))
  46. uri = fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, ""))
  47. }
  48. return uri
  49. }
  50. // ToPath 转化成路径
  51. func ToPath(args ...string) string {
  52. if len(args) == 0 {
  53. return ""
  54. }
  55. strList := make([]string, 0)
  56. for i, p := range args {
  57. if strings.TrimSpace(p) == "" {
  58. continue
  59. }
  60. if i == 0 {
  61. strList = append(strList, strings.TrimRight(strings.TrimSpace(p), "/"))
  62. continue
  63. }
  64. strList = append(strList, strings.Trim(strings.TrimSpace(p), "/"))
  65. }
  66. return strings.Join(strList, "/")
  67. }
  68. // 通过code换取授权access_token
  69. type AccessTokenResp struct {
  70. Code int `json:"code"`
  71. Msg string `json:"msg"`
  72. Data struct {
  73. AccessToken string `json:"accessToken"`
  74. OpenId string `json:"openId"`
  75. NickName string `json:"nickName"`
  76. AvatarUrl string `json:"avatarUrl"`
  77. RefreshToken string `json:"refreshToken"`
  78. UserId int64 `json:"userId"`
  79. } `json:"data"`
  80. }
  81. func AccessToken(code string) (*AccessTokenResp, error) {
  82. uri := "/v1/third/open/oauth2/access_token"
  83. uri = fmt.Sprintf("%s?appId=%s&appSecret=%s&code=%s", uri, conf().Appid, conf().Secret, code)
  84. // get request
  85. uri = ToPath(conf().RootUrl, uri)
  86. return get[AccessTokenResp](uri)
  87. }
  88. type GetUserInfoReq struct {
  89. AppId string `json:"appId"`
  90. //OpenId string `json:"openId"`
  91. UserId string `json:"userId"`
  92. Timestamp string `json:"timestamp"`
  93. Sign string `json:"sign"`
  94. }
  95. type ExchangeUserInfo struct {
  96. InviteCode string `json:"inviteCode"`
  97. ParentInviteCode string `json:"parentInviteCode"`
  98. ParentUserId int64 `json:"parentUserId"`
  99. }
  100. type UserInfoResp struct {
  101. Code int `json:"code"`
  102. Msg string `json:"msg"`
  103. Data *ExchangeUserInfo `json:"data"`
  104. }
  105. func GetUserInviteInfo(userID string) (*ExchangeUserInfo, error) {
  106. uri := "/v1/act/public/application/third/invite-info"
  107. url := ToPath(conf().RootUrl, uri)
  108. req := &GetUserInfoReq{
  109. AppId: conf().Appid,
  110. UserId: userID,
  111. Timestamp: fmt.Sprintf("%d", time.Now().UnixMilli()),
  112. }
  113. reqMap, err := structToJSONMap(req)
  114. if err != nil {
  115. return nil, err
  116. }
  117. sign := signMd5(reqMap)
  118. req.Sign = sign
  119. data, _ := json.Marshal(&req)
  120. t, err := post[UserInfoResp](url, data)
  121. if err != nil {
  122. return nil, err
  123. }
  124. if t != nil && t.Data != nil && t.Code == 200 {
  125. return t.Data, nil
  126. }
  127. return nil, fmt.Errorf("exchange msg:%s code:%d", t.Msg, t.Code)
  128. }
  129. // 刷新access_token(如果需要) get
  130. type RefreshTokenResp struct {
  131. Code int `json:"code"`
  132. Msg string `json:"msg"`
  133. Data struct {
  134. AccessToken string `json:"accessToken"`
  135. OpenId string `json:"openId"`
  136. RefreshToken string `json:"refreshToken"`
  137. } `json:"data"`
  138. }
  139. func RefreshToken(refreshToken string) (*RefreshTokenResp, error) {
  140. uri := "/v1/third/open/oauth2/refresh_token"
  141. uri = fmt.Sprintf("%s?appId=%s&refresh_token=%s", uri, conf().Appid, refreshToken)
  142. uri = ToPath(conf().RootUrl, uri)
  143. return get[RefreshTokenResp](uri)
  144. }
  145. // 检验access_token是否有效 get
  146. type CheckAccessTokenResp struct {
  147. Code int `json:"code"`
  148. Msg string `json:"msg"`
  149. Data bool `json:"data"`
  150. }
  151. func Auth(token string) (*CheckAccessTokenResp, error) {
  152. uri := "/v1/third/open/oauth2/auth"
  153. uri = fmt.Sprintf("%s?accessToken=%s", uri, token)
  154. uri = ToPath(conf().RootUrl, uri)
  155. return get[CheckAccessTokenResp](uri)
  156. }
  157. // 获取用户推荐码
  158. type UserInviteInfoResp struct {
  159. Code int `json:"code"`
  160. Msg string `json:"msg"`
  161. Data struct {
  162. InviteCode string `json:"inviteCode"`
  163. } `json:"data"`
  164. }
  165. // openId 查询邀请码
  166. // 通过openId 获取上级信息 openId 查询邀请码以及上级邀请码和openId
  167. // /v1/act/public/application/third/invite-info-by-openid
  168. type SignParam struct {
  169. AppId string `json:"appId,omitempty"`
  170. OpenId string `json:"openId,omitempty"`
  171. Timestamp string `json:"timestamp,omitempty"`
  172. }
  173. type GetUserInviteInfoReq struct {
  174. AppId string `json:"appId,omitempty"`
  175. OpenId string `json:"openId,omitempty"`
  176. Timestamp string `json:"timestamp,omitempty"`
  177. Sign string `json:"sign,omitempty"`
  178. }
  179. type GetInviteInfoByOpenIdResp struct {
  180. Code int `json:"code"`
  181. Msg string `json:"msg"`
  182. Data struct {
  183. InviteCode string `json:"inviteCode"`
  184. ParentInviteCode string `json:"parentInviteCode"`
  185. ParentOpenId string `json:"parentOpenId"`
  186. } `json:"data"`
  187. }
  188. func GetInviteInfoByOpenId(openId string) (*GetInviteInfoByOpenIdResp, error) {
  189. uri := "/v1/act/public/application/third/invite-info-by-openid"
  190. uri = ToPath(conf().RootUrl, uri)
  191. timestamp := time.Now().UnixMilli()
  192. req := new(GetUserInviteInfoReq)
  193. req.Timestamp = gocast.ToString(timestamp)
  194. req.AppId = conf().Appid
  195. req.OpenId = openId
  196. reqMap, err := structToJSONMap(req)
  197. if err != nil {
  198. return nil, err
  199. }
  200. sign := signMd5(reqMap)
  201. req.Sign = sign
  202. data, _ := json.Marshal(&req)
  203. return post[GetInviteInfoByOpenIdResp](uri, data)
  204. }