oauth.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package oauth
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/url"
  6. "github.com/silenceper/wechat/v2/util"
  7. "github.com/silenceper/wechat/v2/work/context"
  8. )
  9. // Oauth auth
  10. type Oauth struct {
  11. *context.Context
  12. }
  13. var (
  14. // oauthTargetURL 企业微信内跳转地址
  15. oauthTargetURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"
  16. // oauthTargetURL 企业微信内跳转地址(获取成员的详细信息)
  17. oauthTargetPrivateURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_privateinfo&agentid=%s&state=STATE#wechat_redirect"
  18. // oauthUserInfoURL 获取用户信息地址
  19. oauthUserInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s"
  20. // oauthQrContentTargetURL 构造独立窗口登录二维码
  21. oauthQrContentTargetURL = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=%s&agentid=%s&redirect_uri=%s&state=%s"
  22. // getUserInfoURL 获取访问用户身份&获取用户登录身份
  23. getUserInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=%s&code=%s"
  24. // getUserDetailURL 获取访问用户敏感信息
  25. getUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token=%s"
  26. // getTfaInfoURL 获取用户二次验证信息
  27. getTfaInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/auth/get_tfa_info?access_token=%s"
  28. // tfaSuccURL 使用二次验证
  29. tfaSuccURL = "https://qyapi.weixin.qq.com/cgi-bin/user/tfa_succ?access_token=%s"
  30. )
  31. // NewOauth new init oauth
  32. func NewOauth(ctx *context.Context) *Oauth {
  33. return &Oauth{
  34. ctx,
  35. }
  36. }
  37. // GetTargetURL 获取授权地址
  38. func (ctr *Oauth) GetTargetURL(callbackURL string) string {
  39. // url encode
  40. return fmt.Sprintf(
  41. oauthTargetURL,
  42. ctr.CorpID,
  43. url.QueryEscape(callbackURL),
  44. )
  45. }
  46. // GetTargetPrivateURL 获取个人信息授权地址
  47. func (ctr *Oauth) GetTargetPrivateURL(callbackURL string, agentID string) string {
  48. // url encode
  49. return fmt.Sprintf(
  50. oauthTargetPrivateURL,
  51. ctr.CorpID,
  52. url.QueryEscape(callbackURL),
  53. agentID,
  54. )
  55. }
  56. // GetQrContentTargetURL 构造独立窗口登录二维码
  57. func (ctr *Oauth) GetQrContentTargetURL(callbackURL string) string {
  58. // url encode
  59. return fmt.Sprintf(
  60. oauthQrContentTargetURL,
  61. ctr.CorpID,
  62. ctr.AgentID,
  63. url.QueryEscape(callbackURL),
  64. util.RandomStr(16),
  65. )
  66. }
  67. // ResUserInfo 返回得用户信息
  68. type ResUserInfo struct {
  69. util.CommonError
  70. // 当用户为企业成员时返回
  71. UserID string `json:"UserId"`
  72. DeviceID string `json:"DeviceId"`
  73. // 非企业成员授权时返回
  74. OpenID string `json:"OpenId"`
  75. ExternalUserID string `json:"external_userid"`
  76. }
  77. // UserFromCode 根据code获取用户信息
  78. func (ctr *Oauth) UserFromCode(code string) (result ResUserInfo, err error) {
  79. var accessToken string
  80. if accessToken, err = ctr.GetAccessToken(); err != nil {
  81. return
  82. }
  83. var response []byte
  84. if response, err = util.HTTPGet(fmt.Sprintf(oauthUserInfoURL, accessToken, code)); err != nil {
  85. return
  86. }
  87. err = json.Unmarshal(response, &result)
  88. if result.ErrCode != 0 {
  89. err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  90. return
  91. }
  92. return
  93. }
  94. // GetUserInfoResponse 获取访问用户身份&获取用户登录身份响应
  95. type GetUserInfoResponse struct {
  96. util.CommonError
  97. UserID string `json:"userid"`
  98. UserTicket string `json:"user_ticket"`
  99. OpenID string `json:"openid"`
  100. ExternalUserID string `json:"external_userid"`
  101. }
  102. // GetUserInfo 获取访问用户身份&获取用户登录身份
  103. // @see https://developer.work.weixin.qq.com/document/path/90213 获取访问用户身份
  104. // @see https://developer.work.weixin.qq.com/document/path/98176 获取用户登录身份
  105. func (ctr *Oauth) GetUserInfo(code string) (*GetUserInfoResponse, error) {
  106. var (
  107. accessToken string
  108. err error
  109. )
  110. if accessToken, err = ctr.GetAccessToken(); err != nil {
  111. return nil, err
  112. }
  113. var response []byte
  114. if response, err = util.HTTPGet(fmt.Sprintf(getUserInfoURL, accessToken, code)); err != nil {
  115. return nil, err
  116. }
  117. result := &GetUserInfoResponse{}
  118. err = util.DecodeWithError(response, result, "GetUserInfo")
  119. return result, err
  120. }
  121. // GetUserDetailRequest 获取访问用户敏感信息请求
  122. type GetUserDetailRequest struct {
  123. UserTicket string `json:"user_ticket"`
  124. }
  125. // GetUserDetailResponse 获取访问用户敏感信息响应
  126. type GetUserDetailResponse struct {
  127. util.CommonError
  128. UserID string `json:"userid"`
  129. Gender string `json:"gender"`
  130. Avatar string `json:"avatar"`
  131. QrCode string `json:"qr_code"`
  132. Mobile string `json:"mobile"`
  133. Email string `json:"email"`
  134. BizMail string `json:"biz_mail"`
  135. Address string `json:"address"`
  136. }
  137. // GetUserDetail 获取访问用户敏感信息
  138. // @see https://developer.work.weixin.qq.com/document/path/95833
  139. func (ctr *Oauth) GetUserDetail(req *GetUserDetailRequest) (*GetUserDetailResponse, error) {
  140. var (
  141. accessToken string
  142. err error
  143. )
  144. if accessToken, err = ctr.GetAccessToken(); err != nil {
  145. return nil, err
  146. }
  147. var response []byte
  148. if response, err = util.PostJSON(fmt.Sprintf(getUserDetailURL, accessToken), req); err != nil {
  149. return nil, err
  150. }
  151. result := &GetUserDetailResponse{}
  152. err = util.DecodeWithError(response, result, "GetUserDetail")
  153. return result, err
  154. }
  155. // GetTfaInfoRequest 获取用户二次验证信息请求
  156. type GetTfaInfoRequest struct {
  157. Code string `json:"code"`
  158. }
  159. // GetTfaInfoResponse 获取用户二次验证信息响应
  160. type GetTfaInfoResponse struct {
  161. util.CommonError
  162. UserID string `json:"userid"`
  163. TfaCode string `json:"tfa_code"`
  164. }
  165. // GetTfaInfo 获取用户二次验证信息
  166. // @see https://developer.work.weixin.qq.com/document/path/99499
  167. func (ctr *Oauth) GetTfaInfo(req *GetTfaInfoRequest) (*GetTfaInfoResponse, error) {
  168. var (
  169. accessToken string
  170. err error
  171. )
  172. if accessToken, err = ctr.GetAccessToken(); err != nil {
  173. return nil, err
  174. }
  175. var response []byte
  176. if response, err = util.PostJSON(fmt.Sprintf(getTfaInfoURL, accessToken), req); err != nil {
  177. return nil, err
  178. }
  179. result := &GetTfaInfoResponse{}
  180. err = util.DecodeWithError(response, result, "GetTfaInfo")
  181. return result, err
  182. }
  183. // TfaSuccRequest 使用二次验证请求
  184. type TfaSuccRequest struct {
  185. UserID string `json:"userid"`
  186. TfaCode string `json:"tfa_code"`
  187. }
  188. // TfaSucc 使用二次验证
  189. // @see https://developer.work.weixin.qq.com/document/path/99500
  190. func (ctr *Oauth) TfaSucc(req *TfaSuccRequest) error {
  191. var (
  192. accessToken string
  193. err error
  194. )
  195. if accessToken, err = ctr.GetAccessToken(); err != nil {
  196. return err
  197. }
  198. var response []byte
  199. if response, err = util.PostJSON(fmt.Sprintf(tfaSuccURL, accessToken), req); err != nil {
  200. return err
  201. }
  202. return util.DecodeWithCommonError(response, "TfaSucc")
  203. }