servicecontext.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. timestamp := utils.GetTimestamp()
  71. ube, err := json.Marshal(params)
  72. if err != nil {
  73. return "", err
  74. }
  75. err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, timestamp), string(ube), time.Duration(1)*time.Hour)
  76. return fmt.Sprintf("%v", timestamp), err
  77. }
  78. // GenUserQrId defined TODO
  79. func (wc *Wechat) GenUserQrId(prefix string, userId int64, params interface{}) (string, error) {
  80. timestamp := utils.GetTimestamp()
  81. ube, err := json.Marshal(params)
  82. if err != nil {
  83. return "", err
  84. }
  85. qrId := fmt.Sprintf("u%v-%v", userId, timestamp)
  86. err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, qrId), string(ube), time.Duration(1)*time.Hour)
  87. return qrId, err
  88. }
  89. // GetQrParams defined TODO
  90. func (wc *Wechat) GetQrParams(prefix string, id string, params interface{}) error {
  91. ube := ""
  92. err := wc.RdCli.GetCache(fmt.Sprintf(prefix, id), &ube)
  93. if err != nil {
  94. return err
  95. }
  96. err = json.Unmarshal([]byte(ube), params)
  97. if err != nil {
  98. return err
  99. }
  100. return err
  101. }
  102. // GetQrParams defined TODO
  103. func (wc *Wechat) DecryptMobile(sessionKey, encryptedData, iv string) (string, error) {
  104. key, err := base64.StdEncoding.DecodeString(sessionKey)
  105. if err != nil {
  106. return "", err
  107. }
  108. bIv, err := base64.StdEncoding.DecodeString(iv)
  109. if err != nil {
  110. return "", err
  111. }
  112. bEncryptedData, err := base64.StdEncoding.DecodeString(encryptedData)
  113. if err != nil {
  114. return "", err
  115. }
  116. block, err := aes.NewCipher(key)
  117. if err != nil {
  118. return "", err
  119. }
  120. var decrypt = bEncryptedData
  121. blockMode := cipher.NewCBCDecrypter(block, bIv)
  122. blockMode.CryptBlocks(decrypt, bEncryptedData)
  123. length := len(decrypt)
  124. unpadding := int(decrypt[length-1])
  125. decData := decrypt[:(length - unpadding)]
  126. decryptData := WechatPhonedecrypt{}
  127. err = json.Unmarshal(decData, &decryptData)
  128. if err != nil {
  129. return "", err
  130. }
  131. return decryptData.PhoneNumber, err
  132. }
  133. // GenQrCode defined TODO
  134. func (wc *Wechat) GenQrCode(scene, page string) (string, error) {
  135. token, err := wc.GetAccessToken()
  136. if err != nil {
  137. return "", err
  138. }
  139. req := utils.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token)
  140. req.JSONBody(map[string]interface{}{"scene": scene})
  141. ph := path.Join("asserts", "qrcode", scene+".png")
  142. err = req.ToFile(ph)
  143. if err != nil {
  144. return "", err
  145. }
  146. return ph, err
  147. }
  148. type ServiceContext struct {
  149. Config config.Config
  150. SqlConn sqlx.SqlConn
  151. UserModel model.UserModel
  152. RdCli RdCli
  153. Wechat *Wechat
  154. Transformer transformclient.Transform
  155. }
  156. // GetUserId defined TODO
  157. func (sc *ServiceContext) GetClaims(r *http.Request) (int64, string, error) {
  158. parser := token.NewTokenParser(token.WithResetDuration(time.Minute))
  159. tok, err := parser.ParseToken(r, sc.Config.JwtAuth.AccessSecret, "")
  160. if err != nil {
  161. return 0, "", err
  162. }
  163. userId, sessionKey := int64(0), ""
  164. m := tok.Claims.(jwt.MapClaims)
  165. switch nbf := m["userId"].(type) {
  166. case string:
  167. i, err := strconv.ParseInt(nbf, 10, 64)
  168. if err != nil {
  169. return 0, "", err
  170. }
  171. userId = i
  172. case json.Number:
  173. v, err := nbf.Int64()
  174. if err != nil {
  175. return 0, "", err
  176. }
  177. userId = v
  178. }
  179. switch nbf := m["sessionKey"].(type) {
  180. case string:
  181. sessionKey = nbf
  182. case json.Number:
  183. v, err := nbf.Int64()
  184. if err != nil {
  185. return 0, "", err
  186. }
  187. sessionKey = fmt.Sprintf("%v", v)
  188. }
  189. return userId, sessionKey, err
  190. }
  191. func NewServiceContext(c config.Config) *ServiceContext {
  192. svc := &ServiceContext{
  193. Config: c,
  194. SqlConn: sqlx.NewMysql(c.DataSource),
  195. Transformer: transformclient.NewTransform(zrpc.MustNewClient(c.Transform)),
  196. }
  197. svc.UserModel = model.NewUserModel(svc.SqlConn, c.Cache)
  198. svc.RdCli = svc.UserModel.CacheStorage()
  199. svc.Wechat = &Wechat{
  200. RdCli: svc.RdCli,
  201. c: c,
  202. }
  203. return svc
  204. }