diff --git a/biz/container/wire_gen.go b/biz/container/wire_gen.go index f23b637..2851d3c 100644 --- a/biz/container/wire_gen.go +++ b/biz/container/wire_gen.go @@ -25,7 +25,7 @@ func GetContainer(path string) *Container { configConfig := config.InitConfig(path) db := database.NewDatabase(configConfig) iRepository := repo.NewRepository(db) - iUserService := user.NewUserService(iRepository) + iUserService := user.NewUserService(iRepository, configConfig) logger := log.NewLogger() iFileService := file.NewFileService(iRepository, logger) iGlobalService := global_service.NewGlobalService(iRepository, logger) diff --git a/biz/infra/config/config.go b/biz/infra/config/config.go index 421e33f..3c543eb 100644 --- a/biz/infra/config/config.go +++ b/biz/infra/config/config.go @@ -18,9 +18,15 @@ type HttpConfig struct { SecretKey string `yaml:"secret_key"` } +type TencentConfig struct { + APPID int `yaml:"app_id"` + SecretKey string `yaml:"key"` +} + type Config struct { DatabaseConfig DatabaseConfig `yaml:"database"` HttpConfig HttpConfig `yaml:"http"` + TencentConfig TencentConfig `yaml:"tencent"` } func InitConfig(path string) *Config { diff --git a/biz/internal/service/chat/chat.go b/biz/internal/service/chat/chat.go index 10c2118..e3ba0cf 100644 --- a/biz/internal/service/chat/chat.go +++ b/biz/internal/service/chat/chat.go @@ -20,6 +20,7 @@ func (s *ChatService) CreateChat(ctx context.Context, c *app.RequestContext) { } var chatID string + // 防止生成重复聊天id for { chatID = U.RandSeq(4) _, found := s.Cache.Get(chatID) diff --git a/biz/internal/service/global_service/cron.go b/biz/internal/service/global_service/cron.go index 64a631b..d664ef2 100644 --- a/biz/internal/service/global_service/cron.go +++ b/biz/internal/service/global_service/cron.go @@ -5,6 +5,7 @@ import ( "github.com/robfig/cron/v3" "os" "personal-page-be/biz/internal/constant" + "time" ) func (s *GlobalService) DeleteFile() { @@ -17,19 +18,30 @@ func (s *GlobalService) DeleteFile() { if file.IsDir() { continue } - fileEntity, err := s.Repo.FindFileBySaveName(file.Name()) - if err != nil { - panic(err) - } - if fileEntity.ID == 0 || fileEntity.Count == 0 { - filePath := fmt.Sprintf("./%s/%s", constant.FileBasePath, file.Name()) - err = os.Remove(filePath) + maxRetries := 5 // 最大重试次数 + waitInterval := 500 // 初始等待间隔(毫秒) + + for i := 0; i < maxRetries; i++ { + fileEntity, err := s.Repo.FindFileBySaveName(file.Name()) if err != nil { - s.Logger.Error("删除文件失败" + err.Error()) - } else { - s.Logger.Info(fmt.Sprintf("删除文件%s成功", file.Name())) + s.Logger.Error("查询要删除的文件失败:" + err.Error()) + time.Sleep(time.Duration(waitInterval) * time.Millisecond) + waitInterval *= 2 // 指数增长等待间隔 + continue + } + if fileEntity.ID == 0 || fileEntity.Count == 0 { + filePath := fmt.Sprintf("./%s/%s", constant.FileBasePath, file.Name()) + err = os.Remove(filePath) + if err != nil { + s.Logger.Error("删除文件失败" + err.Error()) + } else { + s.Logger.Info(fmt.Sprintf("删除文件%s成功", file.Name())) + } } + break + } + } } func (s *GlobalService) StartCronDeleteFile() { diff --git a/biz/internal/service/user/interface.go b/biz/internal/service/user/interface.go index 3e4ad78..f222367 100644 --- a/biz/internal/service/user/interface.go +++ b/biz/internal/service/user/interface.go @@ -3,11 +3,13 @@ package user import ( "context" "github.com/cloudwego/hertz/pkg/app" + "personal-page-be/biz/infra/config" "personal-page-be/biz/internal/repo" ) type UserService struct { - Repo repo.IRepository + Repo repo.IRepository + Config *config.Config } type IUserService interface { @@ -16,10 +18,12 @@ type IUserService interface { GetUserInfo(ctx context.Context, c *app.RequestContext) GenerateActivateCode(ctx context.Context, c *app.RequestContext) Register(ctx context.Context, c *app.RequestContext) + GenTencentIMUserSig(ctx context.Context, c *app.RequestContext) } -func NewUserService(repo repo.IRepository) IUserService { +func NewUserService(repo repo.IRepository, config *config.Config) IUserService { return &UserService{ - Repo: repo, + Repo: repo, + Config: config, } } diff --git a/biz/internal/service/user/tencent.go b/biz/internal/service/user/tencent.go new file mode 100644 index 0000000..d1c4982 --- /dev/null +++ b/biz/internal/service/user/tencent.go @@ -0,0 +1,430 @@ +package user + +import ( + "bytes" + "compress/zlib" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "errors" + "io/ioutil" + "strconv" + "strings" + "time" +) + +/** + *【功能说明】用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据 + * + *【参数说明】 + * sdkappid - 应用id + * key - 计算 usersig 用的加密密钥,控制台可获取 + * userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 + * expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。 + */ + +/** + * Function: Used to issue UserSig that is required by the TRTC and IM services. + * + * Parameter description: + * sdkappid - Application ID + * userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). + * key - The encryption key used to calculate usersig can be obtained from the console. + * expire - UserSig expiration time, in seconds. For example, 86400 indicates that the generated UserSig will expire one day after being generated. + */ +func GenUserSig(sdkappid int, key string, userid string, expire int) (string, error) { + return genSig(sdkappid, key, userid, expire, nil) +} + +func GenUserSigWithBuf(sdkappid int, key string, userid string, expire int, buf []byte) (string, error) { + return genSig(sdkappid, key, userid, expire, buf) +} + +/** + *【功能说明】 + * 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。 + * PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力: + * - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。 + * - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。 + * 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。 + * + *【参数说明】 + * sdkappid - 应用id。 + * key - 计算 usersig 用的加密密钥,控制台可获取。 + * userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 + * expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。 + * roomid - 房间号,用于指定该 userid 可以进入的房间号 + * privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关: + * - 第 1 位:0000 0001 = 1,创建房间的权限 + * - 第 2 位:0000 0010 = 2,加入房间的权限 + * - 第 3 位:0000 0100 = 4,发送语音的权限 + * - 第 4 位:0000 1000 = 8,接收语音的权限 + * - 第 5 位:0001 0000 = 16,发送视频的权限 + * - 第 6 位:0010 0000 = 32,接收视频的权限 + * - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限 + * - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限 + * - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。 + * - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。 + */ + +/** + * Function: + * Used to issue PrivateMapKey that is optional for room entry. + * PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities. + * - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room. + * - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room. + * To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info. + * + * Parameter description: + * sdkappid - Application ID + * userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). + * key - The encryption key used to calculate usersig can be obtained from the console. + * roomid - ID of the room to which the specified UserID can enter. + * expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated. + * privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features: + * - Bit 1: 0000 0001 = 1, permission for room creation + * - Bit 2: 0000 0010 = 2, permission for room entry + * - Bit 3: 0000 0100 = 4, permission for audio sending + * - Bit 4: 0000 1000 = 8, permission for audio receiving + * - Bit 5: 0001 0000 = 16, permission for video sending + * - Bit 6: 0010 0000 = 32, permission for video receiving + * - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing) + * - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing) + * - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid. + * - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data. + */ + +func GenPrivateMapKey(sdkappid int, key string, userid string, expire int, roomid uint32, privilegeMap uint32) (string, error) { + var userbuf []byte = genUserBuf(userid, sdkappid, roomid, expire, privilegeMap, 0, "") + return genSig(sdkappid, key, userid, expire, userbuf) +} + +/** + *【功能说明】 + * 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。 + * PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力: + * - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。 + * - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。 + * 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。 + * + *【参数说明】 + * sdkappid - 应用id。 + * key - 计算 usersig 用的加密密钥,控制台可获取。 + * userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 + * expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。 + * roomStr - 字符串房间号,用于指定该 userid 可以进入的房间号 + * privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关: + * - 第 1 位:0000 0001 = 1,创建房间的权限 + * - 第 2 位:0000 0010 = 2,加入房间的权限 + * - 第 3 位:0000 0100 = 4,发送语音的权限 + * - 第 4 位:0000 1000 = 8,接收语音的权限 + * - 第 5 位:0001 0000 = 16,发送视频的权限 + * - 第 6 位:0010 0000 = 32,接收视频的权限 + * - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限 + * - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限 + * - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。 + * - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。 + */ + +/** + * Function: + * Used to issue PrivateMapKey that is optional for room entry. + * PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities. + * - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room. + * - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room. + * To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info. + * + * Parameter description: + * sdkappid - Application ID + * userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). + * key - The encryption key used to calculate usersig can be obtained from the console. + * roomstr - ID of the room to which the specified UserID can enter. + * expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated. + * privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features: + * - Bit 1: 0000 0001 = 1, permission for room creation + * - Bit 2: 0000 0010 = 2, permission for room entry + * - Bit 3: 0000 0100 = 4, permission for audio sending + * - Bit 4: 0000 1000 = 8, permission for audio receiving + * - Bit 5: 0001 0000 = 16, permission for video sending + * - Bit 6: 0010 0000 = 32, permission for video receiving + * - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing) + * - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing) + * - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid. + * - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data. + */ +func GenPrivateMapKeyWithStringRoomID(sdkappid int, key string, userid string, expire int, roomStr string, privilegeMap uint32) (string, error) { + var userbuf []byte = genUserBuf(userid, sdkappid, 0, expire, privilegeMap, 0, roomStr) + return genSig(sdkappid, key, userid, expire, userbuf) +} + +func genUserBuf(account string, dwSdkappid int, dwAuthID uint32, + dwExpTime int, dwPrivilegeMap uint32, dwAccountType uint32, roomStr string) []byte { + + offset := 0 + length := 1 + 2 + len(account) + 20 + len(roomStr) + if len(roomStr) > 0 { + length = length + 2 + } + + userBuf := make([]byte, length) + + //ver + if len(roomStr) > 0 { + userBuf[offset] = 1 + } else { + userBuf[offset] = 0 + } + + offset++ + userBuf[offset] = (byte)((len(account) & 0xFF00) >> 8) + offset++ + userBuf[offset] = (byte)(len(account) & 0x00FF) + offset++ + + for ; offset < len(account)+3; offset++ { + userBuf[offset] = account[offset-3] + } + + //dwSdkAppid + userBuf[offset] = (byte)((dwSdkappid & 0xFF000000) >> 24) + offset++ + userBuf[offset] = (byte)((dwSdkappid & 0x00FF0000) >> 16) + offset++ + userBuf[offset] = (byte)((dwSdkappid & 0x0000FF00) >> 8) + offset++ + userBuf[offset] = (byte)(dwSdkappid & 0x000000FF) + offset++ + + //dwAuthId + userBuf[offset] = (byte)((dwAuthID & 0xFF000000) >> 24) + offset++ + userBuf[offset] = (byte)((dwAuthID & 0x00FF0000) >> 16) + offset++ + userBuf[offset] = (byte)((dwAuthID & 0x0000FF00) >> 8) + offset++ + userBuf[offset] = (byte)(dwAuthID & 0x000000FF) + offset++ + + //dwExpTime now+300; + currTime := time.Now().Unix() + var expire = currTime + int64(dwExpTime) + userBuf[offset] = (byte)((expire & 0xFF000000) >> 24) + offset++ + userBuf[offset] = (byte)((expire & 0x00FF0000) >> 16) + offset++ + userBuf[offset] = (byte)((expire & 0x0000FF00) >> 8) + offset++ + userBuf[offset] = (byte)(expire & 0x000000FF) + offset++ + + //dwPrivilegeMap + userBuf[offset] = (byte)((dwPrivilegeMap & 0xFF000000) >> 24) + offset++ + userBuf[offset] = (byte)((dwPrivilegeMap & 0x00FF0000) >> 16) + offset++ + userBuf[offset] = (byte)((dwPrivilegeMap & 0x0000FF00) >> 8) + offset++ + userBuf[offset] = (byte)(dwPrivilegeMap & 0x000000FF) + offset++ + + //dwAccountType + userBuf[offset] = (byte)((dwAccountType & 0xFF000000) >> 24) + offset++ + userBuf[offset] = (byte)((dwAccountType & 0x00FF0000) >> 16) + offset++ + userBuf[offset] = (byte)((dwAccountType & 0x0000FF00) >> 8) + offset++ + userBuf[offset] = (byte)(dwAccountType & 0x000000FF) + offset++ + + if len(roomStr) > 0 { + userBuf[offset] = (byte)((len(roomStr) & 0xFF00) >> 8) + offset++ + userBuf[offset] = (byte)(len(roomStr) & 0x00FF) + offset++ + + for ; offset < length; offset++ { + userBuf[offset] = roomStr[offset-(length-len(roomStr))] + } + } + + return userBuf +} + +func hmacsha256(sdkappid int, key string, identifier string, currTime int64, expire int, base64UserBuf *string) string { + var contentToBeSigned string + contentToBeSigned = "TLS.identifier:" + identifier + "\n" + contentToBeSigned += "TLS.sdkappid:" + strconv.Itoa(sdkappid) + "\n" + contentToBeSigned += "TLS.time:" + strconv.FormatInt(currTime, 10) + "\n" + contentToBeSigned += "TLS.expire:" + strconv.Itoa(expire) + "\n" + if nil != base64UserBuf { + contentToBeSigned += "TLS.userbuf:" + *base64UserBuf + "\n" + } + + h := hmac.New(sha256.New, []byte(key)) + h.Write([]byte(contentToBeSigned)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func base64urlEncode(data []byte) string { + str := base64.StdEncoding.EncodeToString(data) + str = strings.Replace(str, "+", "*", -1) + str = strings.Replace(str, "/", "-", -1) + str = strings.Replace(str, "=", "_", -1) + return str +} + +func base64urlDecode(str string) ([]byte, error) { + str = strings.Replace(str, "_", "=", -1) + str = strings.Replace(str, "-", "/", -1) + str = strings.Replace(str, "*", "+", -1) + return base64.StdEncoding.DecodeString(str) +} + +func genSig(sdkappid int, key string, identifier string, expire int, userbuf []byte) (string, error) { + currTime := time.Now().Unix() + sigDoc := make(map[string]interface{}) + sigDoc["TLS.ver"] = "2.0" + sigDoc["TLS.identifier"] = identifier + sigDoc["TLS.sdkappid"] = sdkappid + sigDoc["TLS.expire"] = expire + sigDoc["TLS.time"] = currTime + var base64UserBuf string + if nil != userbuf { + base64UserBuf = base64.StdEncoding.EncodeToString(userbuf) + sigDoc["TLS.userbuf"] = base64UserBuf + sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, &base64UserBuf) + } else { + sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, nil) + } + + data, err := json.Marshal(sigDoc) + if err != nil { + return "", err + } + + var b bytes.Buffer + w := zlib.NewWriter(&b) + if _, err = w.Write(data); err != nil { + return "", err + } + if err = w.Close(); err != nil { + return "", err + } + return base64urlEncode(b.Bytes()), nil +} + +// VerifyUserSig 检验UserSig在now时间点时是否有效 +// VerifyUserSig Check if UserSig is valid at now time +func VerifyUserSig(sdkappid uint64, key string, userid string, usersig string, now time.Time) error { + sig, err := newUserSig(usersig) + if err != nil { + return err + } + return sig.verify(sdkappid, key, userid, now, nil) +} + +// VerifyUserSigWithBuf 检验带UserBuf的UserSig在now时间点是否有效 +// VerifyUserSigWithBuf Check if UserSig with UserBuf is valid at now +func VerifyUserSigWithBuf(sdkappid uint64, key string, userid string, usersig string, now time.Time, userbuf []byte) error { + sig, err := newUserSig(usersig) + if err != nil { + return err + } + return sig.verify(sdkappid, key, userid, now, userbuf) +} + +type userSig struct { + Version string `json:"TLS.ver,omitempty"` + Identifier string `json:"TLS.identifier,omitempty"` + SdkAppID uint64 `json:"TLS.sdkappid,omitempty"` + Expire int64 `json:"TLS.expire,omitempty"` + Time int64 `json:"TLS.time,omitempty"` + UserBuf []byte `json:"TLS.userbuf,omitempty"` + Sig string `json:"TLS.sig,omitempty"` +} + +func newUserSig(usersig string) (userSig, error) { + b, err := base64urlDecode(usersig) + if err != nil { + return userSig{}, err + } + r, err := zlib.NewReader(bytes.NewReader(b)) + if err != nil { + return userSig{}, err + } + data, err := ioutil.ReadAll(r) + if err != nil { + return userSig{}, err + } + if err = r.Close(); err != nil { + return userSig{}, err + } + var sig userSig + if err = json.Unmarshal(data, &sig); err != nil { + return userSig{}, nil + } + return sig, nil +} + +func (u userSig) verify(sdkappid uint64, key string, userid string, now time.Time, userbuf []byte) error { + if sdkappid != u.SdkAppID { + return ErrSdkAppIDNotMatch + } + if userid != u.Identifier { + return ErrIdentifierNotMatch + } + if now.Unix() > u.Time+u.Expire { + return ErrExpired + } + if userbuf != nil { + if u.UserBuf == nil { + return ErrUserBufTypeNotMatch + } + if !bytes.Equal(userbuf, u.UserBuf) { + return ErrUserBufNotMatch + } + } else if u.UserBuf != nil { + return ErrUserBufTypeNotMatch + } + if u.sign(key) != u.Sig { + return ErrSigNotMatch + } + return nil +} + +func (u userSig) sign(key string) string { + var sb bytes.Buffer + sb.WriteString("TLS.identifier:") + sb.WriteString(u.Identifier) + sb.WriteString("\n") + sb.WriteString("TLS.sdkappid:") + sb.WriteString(strconv.FormatUint(u.SdkAppID, 10)) + sb.WriteString("\n") + sb.WriteString("TLS.time:") + sb.WriteString(strconv.FormatInt(u.Time, 10)) + sb.WriteString("\n") + sb.WriteString("TLS.expire:") + sb.WriteString(strconv.FormatInt(u.Expire, 10)) + sb.WriteString("\n") + if u.UserBuf != nil { + sb.WriteString("TLS.userbuf:") + sb.WriteString(base64.StdEncoding.EncodeToString(u.UserBuf)) + sb.WriteString("\n") + } + + h := hmac.New(sha256.New, []byte(key)) + h.Write(sb.Bytes()) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +// 错误类型 +var ( + ErrSdkAppIDNotMatch = errors.New("sdk appid not match") + ErrIdentifierNotMatch = errors.New("identifier not match") + ErrExpired = errors.New("expired") + ErrUserBufTypeNotMatch = errors.New("userbuf type not match") + ErrUserBufNotMatch = errors.New("userbuf not match") + ErrSigNotMatch = errors.New("sig not match") +) diff --git a/biz/internal/service/user/user.go b/biz/internal/service/user/user.go index 7f5fa33..5b3613a 100644 --- a/biz/internal/service/user/user.go +++ b/biz/internal/service/user/user.go @@ -56,22 +56,72 @@ func (s *UserService) Login(ctx context.Context, c *app.RequestContext) { return } - if findUser.IsActivate == false { + session := sessions.Default(c) + session.Set("username", user.Username) + session.Save() + + c.JSON(consts.StatusOK, utils.H{ + "code": 0, + "msg": "登陆成功", + "data": assembler.UserEntityToDTO(findUser), + }) +} + +func (s *UserService) GenTencentIMUserSig(ctx context.Context, c *app.RequestContext) { + var user domain.UserEntity + err := c.BindAndValidate(&user) + if err != nil { + c.JSON(consts.StatusOK, utils.H{ + "code": 5001, + "msg": err.Error(), + }) + return + } + findUser, err := s.Repo.FindUser(user.Username) + if err != nil { + c.JSON(consts.StatusOK, utils.H{ + "code": 5001, + "msg": err.Error(), + }) + return + } + if !findUser.IsActivate { c.JSON(consts.StatusOK, utils.H{ "code": 4003, - "msg": "您的账户未激活,请使用激活码激活", + "msg": "用户未注册激活,请注册后使用", }) return } - session := sessions.Default(c) - session.Set("username", user.Username) - session.Save() + err = bcrypt.CompareHashAndPassword([]byte(findUser.Password), []byte(user.Password)) + if findUser.ID == 0 || err != nil { + c.JSON(consts.StatusOK, utils.H{ + "code": 4003, + "msg": "用户名或密码错误", + }) + return + } + if findUser.CanUse == false { + c.JSON(consts.StatusOK, utils.H{ + "code": 4003, + "msg": "抱歉,您的账户已被禁用", + }) + return + } + tencentConfig := s.Config.TencentConfig + userSigStr, err := GenUserSig(tencentConfig.APPID, tencentConfig.SecretKey, findUser.Username, 24*60*60*180) + if err != nil { + c.JSON(consts.StatusOK, utils.H{ + "code": 4003, + "msg": "获取UserSig调用API失败", + }) + return + } c.JSON(consts.StatusOK, utils.H{ "code": 0, - "msg": "登陆成功", - "data": assembler.UserEntityToDTO(findUser), + "msg": "获取成功", + "data": userSigStr, }) } diff --git a/router.go b/router.go index ba1d004..3f55e10 100644 --- a/router.go +++ b/router.go @@ -17,6 +17,7 @@ func customizedRegister(r *server.Hertz) { userApi.GET("/logout", App.UserService.Logout) userApi.GET("/me", append(middlewire.UserMiddleware(), App.UserService.GetUserInfo)...) userApi.POST("/activate-code", append(middlewire.UserMiddleware(), App.UserService.GenerateActivateCode)...) + userApi.POST("/tencent-usersig", App.UserService.GenTencentIMUserSig) userApi.POST("/register", App.UserService.Register) fileApi := api.Group("/files")