alipay.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package realname
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "math/rand"
  7. "net/url"
  8. "regexp"
  9. "time"
  10. "go-common/app/interface/main/account/conf"
  11. "go-common/app/interface/main/account/model"
  12. memmodel "go-common/app/service/main/member/model"
  13. "go-common/library/ecode"
  14. "go-common/library/log"
  15. "github.com/pkg/errors"
  16. )
  17. var (
  18. _idCard18Regexp = regexp.MustCompile(`^\d{17}[\d|x]$`)
  19. _idCard15Regexp = regexp.MustCompile(`^\d{15}$`)
  20. )
  21. // AlipayApply 提交芝麻认证申请
  22. func (s *Service) AlipayApply(c context.Context, mid int64, param *model.ParamRealnameAlipayApply) (res *model.RealnameAlipayApply, err error) {
  23. if !s.alipayAntispamCheck(c, mid) {
  24. err = ecode.RealnameAlipayAntispam
  25. return
  26. }
  27. if !s.checkID(param.CardNum) {
  28. err = ecode.RealnameCardNumErr
  29. return
  30. }
  31. var bizno string
  32. if bizno, err = s.alipayInit(c, param.Realname, param.CardNum); err != nil {
  33. return
  34. }
  35. res = &model.RealnameAlipayApply{}
  36. if res.URL, err = s.alipayCertifyURL(c, bizno); err != nil {
  37. return
  38. }
  39. var (
  40. arg = &memmodel.ArgRealnameAlipayApply{
  41. MID: mid,
  42. CaptureCode: param.Capture,
  43. Realname: param.Realname,
  44. CardCode: param.CardNum,
  45. IMGToken: param.ImgToken,
  46. Bizno: bizno,
  47. }
  48. )
  49. if err = s.memRPC.RealnameAlipayApply(c, arg); err != nil {
  50. res = nil
  51. return
  52. }
  53. s.addmiss(func() {
  54. if missErr := s.alipayAntispamIncrease(context.Background(), mid); missErr != nil {
  55. log.Error("%+v", err)
  56. }
  57. })
  58. return
  59. }
  60. func (s *Service) checkID(card string) bool {
  61. if !_idCard15Regexp.MatchString(card) && !_idCard18Regexp.MatchString(card) {
  62. return false
  63. }
  64. return true
  65. }
  66. func (s *Service) alipayInit(c context.Context, realname, cardNum string) (bizno string, err error) {
  67. var (
  68. biz struct {
  69. TransID string `json:"transaction_id"`
  70. ProdCode string `json:"product_code"`
  71. BizCode string `json:"biz_code"`
  72. IdenParam struct {
  73. IdentityType string `json:"identity_type"`
  74. CertType string `json:"cert_type"`
  75. CertName string `json:"cert_name"`
  76. CertNo string `json:"cert_no"`
  77. } `json:"identity_param"`
  78. }
  79. param url.Values
  80. )
  81. biz.TransID = s.alipayTransactionID() // 商户请求的唯一标志,32位长度的字母数字下划线组合。该标识作为对账的关键信息,商户要保证其唯一性.
  82. biz.ProdCode = "w1010100000000002978" // 芝麻认证产品码
  83. biz.BizCode = "FACE" // 认证场景码,支持的场景码有: FACE:多因子活体人脸认证, SMART_FACE:多因子快捷活体人脸认证, FACE_SDK:SDK活体人脸认证 签约的协议决定了可以使用的场景
  84. biz.IdenParam.IdentityType = "CERT_INFO"
  85. biz.IdenParam.CertType = "IDENTITY_CARD"
  86. biz.IdenParam.CertName = realname
  87. biz.IdenParam.CertNo = cardNum
  88. if param, err = s.alipayParam("zhima.customer.certification.initialize", biz, ""); err != nil {
  89. return
  90. }
  91. if bizno, err = s.realnameDao.AlipayInit(c, param); err != nil {
  92. log.Error("%+v", err)
  93. err = ecode.RealnameAlipayErr
  94. return
  95. }
  96. if bizno == "" {
  97. err = ecode.RealnameAlipayErr
  98. return
  99. }
  100. return
  101. }
  102. func (s *Service) alipayCertifyURL(c context.Context, bizno string) (u string, err error) {
  103. var (
  104. param url.Values
  105. biz struct {
  106. Bizno string `json:"biz_no"`
  107. }
  108. )
  109. biz.Bizno = bizno
  110. if param, err = s.alipayParam("zhima.customer.certification.certify", biz, "bilibili://auth.zhima"); err != nil {
  111. return
  112. }
  113. u = conf.Conf.Realname.Alipay.Gateway + "?" + param.Encode()
  114. return
  115. }
  116. // AlipayConfirm 查询芝麻认证状态
  117. func (s *Service) AlipayConfirm(c context.Context, mid int64) (res *model.RealnameAlipayConfirm, err error) {
  118. var (
  119. pass bool
  120. reason string
  121. rpcarg = &memmodel.ArgMemberMid{
  122. Mid: mid,
  123. }
  124. rpcres *memmodel.RealnameAlipayInfo
  125. )
  126. if rpcres, err = s.memRPC.RealnameAlipayBizno(c, rpcarg); err != nil {
  127. return
  128. }
  129. if pass, reason, err = s.alipayQuery(c, rpcres.Bizno); err != nil {
  130. log.Error("%+v", err)
  131. err = ecode.RealnameAlipayErr
  132. return
  133. }
  134. res = &model.RealnameAlipayConfirm{
  135. Reason: reason,
  136. }
  137. if pass {
  138. res.Passed = model.RealnameTrue
  139. } else {
  140. res.Passed = model.RealnameFalse
  141. }
  142. // rpc call
  143. var (
  144. rpcConfirmArg = &memmodel.ArgRealnameAlipayConfirm{
  145. MID: mid,
  146. Pass: pass,
  147. Reason: reason,
  148. }
  149. )
  150. if err = s.memRPC.RealnameAlipayConfirm(c, rpcConfirmArg); err != nil {
  151. return
  152. }
  153. s.addmiss(func() {
  154. if missErr := s.setAlipayAntispamPassFlag(context.Background(), mid, false); missErr != nil {
  155. log.Error("%+v", err)
  156. }
  157. })
  158. return
  159. }
  160. func (s *Service) alipayQuery(c context.Context, bizno string) (pass bool, reason string, err error) {
  161. var (
  162. param url.Values
  163. biz struct {
  164. Bizno string `json:"biz_no"`
  165. }
  166. )
  167. biz.Bizno = bizno
  168. if param, err = s.alipayParam("zhima.customer.certification.query", biz, ""); err != nil {
  169. return
  170. }
  171. if pass, reason, err = s.realnameDao.AlipayQuery(c, param); err != nil {
  172. log.Error("%+v", err)
  173. err = ecode.RealnameAlipayErr
  174. return
  175. }
  176. return
  177. }
  178. // alipayParam 构造阿里请求param,biz为 biz_content struct
  179. func (s *Service) alipayParam(method string, biz interface{}, returnURL string) (p url.Values, err error) {
  180. var (
  181. sign string
  182. bizBytes []byte
  183. )
  184. if bizBytes, err = json.Marshal(biz); err != nil {
  185. err = errors.WithStack(err)
  186. return
  187. }
  188. p = url.Values{}
  189. p.Set("app_id", conf.Conf.Realname.Alipay.AppID)
  190. p.Set("method", method)
  191. p.Set("charset", "utf-8")
  192. p.Set("sign_type", "RSA2")
  193. p.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
  194. p.Set("version", "1.0")
  195. p.Set("biz_content", string(bizBytes))
  196. if returnURL != "" {
  197. p.Set("return_url", returnURL)
  198. }
  199. if sign, err = s.alipayCryptor.SignParam(p); err != nil {
  200. return
  201. }
  202. p.Set("sign", sign)
  203. return
  204. }
  205. func (s *Service) alipayTransactionID() string {
  206. return fmt.Sprintf("BILI%d%d", time.Now().UnixNano(), rand.Intn(100000))
  207. }