servicecontext.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package svc
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "encoding/base64"
  6. "encoding/json"
  7. "fmt"
  8. "net/http"
  9. "path"
  10. "strconv"
  11. "time"
  12. "git.i2edu.net/i2/go-zero/core/stores/sqlx"
  13. "git.i2edu.net/i2/go-zero/rest/token"
  14. "git.i2edu.net/i2/go-zero/zrpc"
  15. "git.i2edu.net/i2/i2-bill-api/internal/config"
  16. "git.i2edu.net/i2/i2-bill-api/internal/utils"
  17. "git.i2edu.net/i2/i2-bill-api/model"
  18. "git.i2edu.net/i2/i2-bill-erp/transformclient"
  19. "github.com/dgrijalva/jwt-go"
  20. )
  21. const cacheWechatTokenPrefix = "cache:wechat:token:"
  22. // RdCli defined
  23. type RdCli interface {
  24. SetCache(key string, v interface{}) error
  25. GetCache(key string, v interface{}) error
  26. SetWithExpire(key string, v interface{}, expire time.Duration) error
  27. }
  28. // Wechat defined
  29. type Wechat struct {
  30. RdCli RdCli
  31. c config.Config
  32. }
  33. // WechatPhonedecrypt defined TODO
  34. type WechatPhonedecrypt struct {
  35. PhoneNumber string `json:"phoneNumber"`
  36. PurePhoneNumber string `json:"purePhoneNumber"`
  37. CountryCode string `json:"countryCode"`
  38. Watermark struct {
  39. Appid string `json:"appid"`
  40. Timestamp int32 `json:"timestamp"`
  41. } `json:"watermark"`
  42. }
  43. // GetAccessToken defined TODO
  44. func (wc *Wechat) GetAccessToken() (string, error) {
  45. token := ""
  46. err := wc.RdCli.GetCache(cacheWechatTokenPrefix, &token)
  47. if err == model.ErrRdsNotFound {
  48. req := utils.Get("https://api.weixin.qq.com/cgi-bin/token")
  49. req.Param("grant_type", "client_credential")
  50. req.Param("secret", wc.c.Weixin.Secret)
  51. req.Param("appid", wc.c.Weixin.Appid)
  52. var res = struct {
  53. AccessToken string `json:"access_token"`
  54. ExpiresIn int `json:"expires_in"`
  55. }{}
  56. err = req.ToJSON(&res)
  57. if err != nil {
  58. return "", err
  59. }
  60. token = res.AccessToken
  61. err := wc.RdCli.SetWithExpire(cacheWechatTokenPrefix, res.AccessToken, time.Duration((res.ExpiresIn-60*2))*time.Second)
  62. if err != nil {
  63. return "", err
  64. }
  65. }
  66. return token, nil
  67. }
  68. // GenQrId defined TODO
  69. func (wc *Wechat) GenQrId(prefix string, params interface{}) (string, error) {
  70. uuid := utils.GetUUID()
  71. ube, err := json.Marshal(params)
  72. if err != nil {
  73. return "", err
  74. }
  75. err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, uuid), string(ube), time.Duration(1)*time.Hour)
  76. return uuid, err
  77. }
  78. // GetQrParams defined TODO
  79. func (wc *Wechat) GetQrParams(prefix string, uuid string, params interface{}) error {
  80. ube := ""
  81. err := wc.RdCli.GetCache(fmt.Sprintf(prefix, uuid), &ube)
  82. if err != nil {
  83. return err
  84. }
  85. err = json.Unmarshal([]byte(ube), params)
  86. if err != nil {
  87. return err
  88. }
  89. return err
  90. }
  91. // GetQrParams defined TODO
  92. func (wc *Wechat) DecryptMobile(sessionKey, encryptedData, iv string) (string, error) {
  93. key, err := base64.StdEncoding.DecodeString(sessionKey)
  94. if err != nil {
  95. return "", err
  96. }
  97. bIv, err := base64.StdEncoding.DecodeString(iv)
  98. if err != nil {
  99. return "", err
  100. }
  101. bEncryptedData, err := base64.StdEncoding.DecodeString(encryptedData)
  102. if err != nil {
  103. return "", err
  104. }
  105. block, err := aes.NewCipher(key)
  106. if err != nil {
  107. return "", err
  108. }
  109. var decrypt = bEncryptedData
  110. blockMode := cipher.NewCBCDecrypter(block, bIv)
  111. blockMode.CryptBlocks(decrypt, bEncryptedData)
  112. length := len(decrypt)
  113. unpadding := int(decrypt[length-1])
  114. decData := decrypt[:(length - unpadding)]
  115. decryptData := WechatPhonedecrypt{}
  116. err = json.Unmarshal(decData, &decryptData)
  117. if err != nil {
  118. return "", err
  119. }
  120. return decryptData.PhoneNumber, err
  121. }
  122. // GenQrCode defined TODO
  123. func (wc *Wechat) GenQrCode(scene, page string) (string, error) {
  124. token, err := wc.GetAccessToken()
  125. if err != nil {
  126. return "", err
  127. }
  128. req := utils.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token)
  129. req.JSONBody(map[string]interface{}{"scene": scene})
  130. ph := path.Join("asserts", "qrcode", scene+".png")
  131. err = req.ToFile(ph)
  132. if err != nil {
  133. return "", err
  134. }
  135. return ph, err
  136. }
  137. type ServiceContext struct {
  138. Config config.Config
  139. SqlConn sqlx.SqlConn
  140. UserModel model.UserModel
  141. RdCli RdCli
  142. Wechat *Wechat
  143. Transformer transformclient.Transform
  144. }
  145. // GetUserId defined TODO
  146. func (sc *ServiceContext) GetUserId(r *http.Request) (int64, error) {
  147. parser := token.NewTokenParser(token.WithResetDuration(time.Minute))
  148. tok, err := parser.ParseToken(r, sc.Config.JwtAuth.AccessSecret, "")
  149. if err != nil {
  150. return 0, err
  151. }
  152. m := tok.Claims.(jwt.MapClaims)
  153. switch nbf := m["userId"].(type) {
  154. case string:
  155. i, _ := strconv.ParseInt(nbf, 10, 64)
  156. return i, err
  157. case json.Number:
  158. v, _ := nbf.Int64()
  159. return v, err
  160. }
  161. return 0, err
  162. }
  163. // GetSessionKey defined TODO
  164. func (sc *ServiceContext) GetSessionKey(r *http.Request) (string, error) {
  165. parser := token.NewTokenParser(token.WithResetDuration(time.Minute))
  166. tok, err := parser.ParseToken(r, sc.Config.JwtAuth.AccessSecret, "")
  167. if err != nil {
  168. return "", err
  169. }
  170. m := tok.Claims.(jwt.MapClaims)
  171. switch nbf := m["sessionKey"].(type) {
  172. case string:
  173. return nbf, err
  174. case json.Number:
  175. v, _ := nbf.Int64()
  176. return fmt.Sprintf("%v", v), err
  177. }
  178. return "", err
  179. }
  180. func NewServiceContext(c config.Config) *ServiceContext {
  181. svc := &ServiceContext{
  182. Config: c,
  183. SqlConn: sqlx.NewMysql(c.DataSource),
  184. Transformer: transformclient.NewTransform(zrpc.MustNewClient(c.Transform)),
  185. }
  186. svc.UserModel = model.NewUserModel(svc.SqlConn, c.Cache)
  187. svc.RdCli = svc.UserModel.CacheStorage()
  188. svc.Wechat = &Wechat{
  189. RdCli: svc.RdCli,
  190. c: c,
  191. }
  192. return svc
  193. }