oauth.go 4.7 KB

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