feishu.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package service
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "errors"
  6. "gadmin/config"
  7. "gadmin/internal/admin/forms"
  8. "gadmin/internal/admin/library/feishu"
  9. "gadmin/internal/gorm/model"
  10. "gadmin/internal/gorm/query"
  11. "gadmin/utility/serializer"
  12. "gadmin/utility/token"
  13. "github.com/gin-gonic/gin"
  14. jsoniter "github.com/json-iterator/go"
  15. "github.com/larksuite/oapi-sdk-go/v3/core"
  16. "github.com/larksuite/oapi-sdk-go/v3/service/authen/v1"
  17. "github.com/sirupsen/logrus"
  18. "gorm.io/gorm"
  19. "strconv"
  20. "strings"
  21. "time"
  22. )
  23. var FeiShu = new(feishuService)
  24. type feishuService struct{}
  25. func (s *feishuService) FeiShuUserLogin(c *gin.Context) serializer.Response {
  26. q := query.Use(config.AdminDB).AdminUser
  27. encodeToken := token.GetAuthorization(c)
  28. if encodeToken != "" {
  29. bytesT, err := base64.URLEncoding.DecodeString(encodeToken)
  30. if err != nil {
  31. logrus.Warningf("middleware base64.URLEncoding.DecodeString:%+v", err.Error())
  32. return serializer.CheckLogin()
  33. }
  34. t := string(bytesT)
  35. tokenKey := config.GetTokenKey(t)
  36. if config.TokenRedis.Exists(tokenKey).Val() == 0 {
  37. return serializer.CheckLogin()
  38. }
  39. userStr := config.TokenRedis.Get(tokenKey).Val()
  40. claims := new(token.UserClaims)
  41. if err := jsoniter.UnmarshalFromString(userStr, claims); err != nil {
  42. return serializer.CheckLogin()
  43. }
  44. // 查询登录token是否有效
  45. key := config.GetUserTokenKey(claims.ID)
  46. tokenCTStr := config.TokenRedis.HGet(key, t).Val()
  47. tokenCreateTime, err := strconv.Atoi(tokenCTStr)
  48. if err != nil {
  49. logrus.Warningf("middleware config.LogRedis.HGet:%+v", err.Error())
  50. return serializer.CheckLogin()
  51. }
  52. tokenCT := time.Unix(int64(tokenCreateTime), 0)
  53. if tokenCT.Before(time.Now().Add(-config.TokenExpireTime)) {
  54. return serializer.CheckLogin()
  55. }
  56. u, err := q.Where(q.ID.Eq(claims.ID)).First()
  57. if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
  58. return serializer.Err(2, "", err)
  59. }
  60. if u.Status != 1 {
  61. return serializer.ParamErr("账号已被禁用", nil)
  62. }
  63. user := &token.UserClaims{
  64. ID: u.ID,
  65. UserName: u.UserName,
  66. RoleId: int64(u.RoleID),
  67. Avatar: u.Avatar,
  68. Nickname: u.Nickname,
  69. AccessToken: t,
  70. }
  71. userStr, _ = jsoniter.MarshalToString(user)
  72. config.TokenRedis.HSet(key, t, time.Now().Unix())
  73. config.TokenRedis.Expire(key, config.TokenExpireTime)
  74. config.TokenRedis.Set(tokenKey, userStr, config.TokenExpireTime)
  75. return serializer.Suc(forms.UserLoginRes{
  76. ID: u.ID,
  77. UserName: u.UserName,
  78. Nickname: u.Nickname,
  79. Status: u.Status,
  80. Avatar: u.Avatar,
  81. Token: encodeToken,
  82. })
  83. }
  84. code := c.Query("code")
  85. if code == "" {
  86. return serializer.ParamErr("code is empty", nil)
  87. }
  88. feishuUserInfo, err := s.GetFeiShuUserByCode(code)
  89. if err != nil {
  90. return serializer.Err(1, "", err)
  91. }
  92. if feishuUserInfo == nil {
  93. return serializer.Err(1, "获取用户信息失败", nil)
  94. }
  95. u, err := q.Where(q.FeishuUnionID.Eq(*feishuUserInfo.UnionId)).First()
  96. if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
  97. return serializer.Err(2, "", err)
  98. }
  99. if u == nil {
  100. // 不存在,创建
  101. u = &model.AdminUser{
  102. UserName: *feishuUserInfo.Name,
  103. Nickname: *feishuUserInfo.Name,
  104. Avatar: *feishuUserInfo.AvatarUrl,
  105. //Mobile: *feishuUserInfo.Mobile,
  106. FeishuUnionID: *feishuUserInfo.UnionId,
  107. CreatedAt: time.Now(),
  108. }
  109. if err = q.WithContext(context.Background()).Create(u); err != nil {
  110. return serializer.DBErr(err.Error(), err)
  111. }
  112. return serializer.Err(9999, "注册成功,请联系管理员分配权限!", nil)
  113. }
  114. if u.Status != 1 {
  115. return serializer.ParamErr("账号已被禁用", nil)
  116. }
  117. if u.RoleID == 0 {
  118. return serializer.Err(9999, "请联系管理员分配权限!", nil)
  119. }
  120. t := token.GenerateTokenUsingUUID()
  121. // 记录登录token
  122. key := config.GetUserTokenKey(u.ID)
  123. config.TokenRedis.HSet(key, t, time.Now().Unix())
  124. config.TokenRedis.Expire(key, config.TokenExpireTime)
  125. tokenKey := config.GetTokenKey(t)
  126. user := &token.UserClaims{
  127. ID: u.ID,
  128. UserName: u.UserName,
  129. RoleId: int64(u.RoleID),
  130. Avatar: u.Avatar,
  131. Nickname: u.Nickname,
  132. AccessToken: t,
  133. }
  134. userStr, err := jsoniter.MarshalToString(user)
  135. if err != nil {
  136. return serializer.Err(1, "", err)
  137. }
  138. config.TokenRedis.Set(tokenKey, userStr, config.TokenExpireTime)
  139. return serializer.Suc(forms.UserLoginRes{
  140. ID: u.ID,
  141. UserName: u.UserName,
  142. Nickname: u.Nickname,
  143. Status: u.Status,
  144. Avatar: u.Avatar,
  145. Token: base64.URLEncoding.EncodeToString([]byte(t)),
  146. })
  147. }
  148. func (s *feishuService) GetFeiShuUserByCode(code string) (*larkauthen.GetUserInfoRespData, error) {
  149. // 使用获取到的 code 获取 token
  150. req := larkauthen.NewCreateAccessTokenReqBuilder().Body(
  151. larkauthen.NewCreateAccessTokenReqBodyBuilder().
  152. GrantType("authorization_code").
  153. Code(code).
  154. Build(),
  155. ).Build()
  156. resp, err := feishu.LarkClient.Authen.V1.AccessToken.Create(context.Background(), req)
  157. if err != nil {
  158. logrus.Warnf("GetAccessToken() failed with '%s'\n", err)
  159. return nil, err
  160. }
  161. if !resp.Success() {
  162. logrus.Warnf("logId: %s, error response: \n%s", resp.RequestId(), larkcore.Prettify(resp.CodeError))
  163. return nil, err
  164. }
  165. userInfoResp, err := feishu.LarkClient.Authen.V1.UserInfo.Get(context.Background(), larkcore.WithUserAccessToken(*resp.Data.AccessToken))
  166. // 处理错误
  167. if err != nil {
  168. logrus.Warnf("GetUserInfo() failed with '%s'\n", err)
  169. return nil, err
  170. }
  171. // 服务端错误处理
  172. if !userInfoResp.Success() {
  173. logrus.Warnf("logId: %s, error response: \n%s", userInfoResp.RequestId(), larkcore.Prettify(userInfoResp.CodeError))
  174. return nil, errors.New(larkcore.Prettify(userInfoResp.CodeError))
  175. }
  176. return userInfoResp.Data, nil
  177. }
  178. // 取出手机号码
  179. func extractPhoneNumber(phone string) string {
  180. // 定义可能的国际前缀列表
  181. prefixes := []string{"+86", "86"}
  182. for _, prefix := range prefixes {
  183. if strings.HasPrefix(phone, prefix) {
  184. // 如果手机号以该前缀开头,则返回去掉前缀后的部分
  185. return strings.TrimPrefix(phone, prefix)
  186. }
  187. }
  188. // 如果没有匹配的前缀,直接返回原号码
  189. return phone
  190. }