oauth.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package oauth
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "github.com/silenceper/wechat/context"
  8. "github.com/silenceper/wechat/util"
  9. )
  10. const (
  11. redirectOauthURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"
  12. accessTokenURL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
  13. refreshAccessTokenURL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"
  14. userInfoURL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN"
  15. checkAccessTokenURL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s"
  16. )
  17. //Oauth 保存用户授权信息
  18. type Oauth struct {
  19. *context.Context
  20. }
  21. //NewOauth 实例化授权信息
  22. func NewOauth(context *context.Context) *Oauth {
  23. auth := new(Oauth)
  24. auth.Context = context
  25. return auth
  26. }
  27. //GetRedirectURL 获取跳转的url地址
  28. func (oauth *Oauth) GetRedirectURL(redirectURI, scope, state string) (string, error) {
  29. //url encode
  30. urlStr := url.QueryEscape(redirectURI)
  31. return fmt.Sprintf(redirectOauthURL, oauth.AppID, urlStr, scope, state), nil
  32. }
  33. //Redirect 跳转到网页授权
  34. func (oauth *Oauth) Redirect(writer http.ResponseWriter, req *http.Request, redirectURI, scope, state string) error {
  35. location, err := oauth.GetRedirectURL(redirectURI, scope, state)
  36. if err != nil {
  37. return err
  38. }
  39. http.Redirect(writer, req, location, 302)
  40. return nil
  41. }
  42. // ResAccessToken 获取用户授权access_token的返回结果
  43. type ResAccessToken struct {
  44. util.CommonError
  45. AccessToken string `json:"access_token"`
  46. ExpiresIn int64 `json:"expires_in"`
  47. RefreshToken string `json:"refresh_token"`
  48. OpenID string `json:"openid"`
  49. Scope string `json:"scope"`
  50. // UnionID 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
  51. // 公众号文档 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
  52. UnionID string `json:"unionid"`
  53. }
  54. // GetUserAccessToken 通过网页授权的code 换取access_token(区别于context中的access_token)
  55. func (oauth *Oauth) GetUserAccessToken(code string) (result ResAccessToken, err error) {
  56. urlStr := fmt.Sprintf(accessTokenURL, oauth.AppID, oauth.AppSecret, code)
  57. var response []byte
  58. response, err = util.HTTPGet(urlStr)
  59. if err != nil {
  60. return
  61. }
  62. err = json.Unmarshal(response, &result)
  63. if err != nil {
  64. return
  65. }
  66. if result.ErrCode != 0 {
  67. err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  68. return
  69. }
  70. return
  71. }
  72. //RefreshAccessToken 刷新access_token
  73. func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessToken, err error) {
  74. urlStr := fmt.Sprintf(refreshAccessTokenURL, oauth.AppID, refreshToken)
  75. var response []byte
  76. response, err = util.HTTPGet(urlStr)
  77. if err != nil {
  78. return
  79. }
  80. err = json.Unmarshal(response, &result)
  81. if err != nil {
  82. return
  83. }
  84. if result.ErrCode != 0 {
  85. err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  86. return
  87. }
  88. return
  89. }
  90. //CheckAccessToken 检验access_token是否有效
  91. func (oauth *Oauth) CheckAccessToken(accessToken, openID string) (b bool, err error) {
  92. urlStr := fmt.Sprintf(checkAccessTokenURL, accessToken, openID)
  93. var response []byte
  94. response, err = util.HTTPGet(urlStr)
  95. if err != nil {
  96. return
  97. }
  98. var result util.CommonError
  99. err = json.Unmarshal(response, &result)
  100. if err != nil {
  101. return
  102. }
  103. if result.ErrCode != 0 {
  104. b = false
  105. return
  106. }
  107. b = true
  108. return
  109. }
  110. //UserInfo 用户授权获取到用户信息
  111. type UserInfo struct {
  112. util.CommonError
  113. OpenID string `json:"openid"`
  114. Nickname string `json:"nickname"`
  115. Sex int32 `json:"sex"`
  116. Province string `json:"province"`
  117. City string `json:"city"`
  118. Country string `json:"country"`
  119. HeadImgURL string `json:"headimgurl"`
  120. Privilege []string `json:"privilege"`
  121. Unionid string `json:"unionid"`
  122. }
  123. //GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息
  124. func (oauth *Oauth) GetUserInfo(accessToken, openID string) (result UserInfo, err error) {
  125. urlStr := fmt.Sprintf(userInfoURL, accessToken, openID)
  126. var response []byte
  127. response, err = util.HTTPGet(urlStr)
  128. if err != nil {
  129. return
  130. }
  131. err = json.Unmarshal(response, &result)
  132. if err != nil {
  133. return
  134. }
  135. if result.ErrCode != 0 {
  136. err = fmt.Errorf("GetUserInfo error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  137. return
  138. }
  139. return
  140. }