🔨 refactor code

This commit is contained in:
landaiqing
2024-10-03 02:10:14 +08:00
parent 230921fa3d
commit 16616e3755
17 changed files with 563 additions and 661 deletions

View File

@@ -1,6 +1,6 @@
package enum package enum
var ( var (
Male = "" Male = "Male"
Female = "" Female = "Female"
) )

View File

@@ -135,120 +135,103 @@ func GetGiteeUserInfo(token *Token) (map[string]interface{}, error) {
// @Produce json // @Produce json
// @Router /controller/oauth/gitee/callback [get] // @Router /controller/oauth/gitee/callback [get]
func (OAuthController) GiteeCallback(c *gin.Context) { func (OAuthController) GiteeCallback(c *gin.Context) {
var err error
// 获取 code // 获取 code
var code = c.Query("code") code := c.Query("code")
if code == "" { if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
// 异步获取 token // 获取 token
var tokenChan = make(chan *Token) tokenAuthUrl := GetGiteeTokenAuthUrl(code)
var errChan = make(chan error) token, err := GetGiteeToken(tokenAuthUrl)
go func() { if err != nil {
var tokenAuthUrl = GetGiteeTokenAuthUrl(code)
token, err := GetGiteeToken(tokenAuthUrl)
if err != nil {
errChan <- err
return
}
tokenChan <- token
}()
// 异步获取用户信息
var userInfoChan = make(chan map[string]interface{})
go func() {
token := <-tokenChan
if token == nil {
errChan <- errors.New("failed to get token")
return
}
userInfo, err := GetGiteeUserInfo(token)
if err != nil {
errChan <- err
return
}
userInfoChan <- userInfo
}()
// 等待结果
select {
case err = <-errChan:
global.LOG.Error(err) global.LOG.Error(err)
return return
case userInfo := <-userInfoChan: }
userInfoBytes, err := json.Marshal(userInfo) if token == nil {
if err != nil { global.LOG.Error(errors.New("failed to get token"))
global.LOG.Error(err)
return
}
var giteeUser GiteeUser
err = json.Unmarshal(userInfoBytes, &giteeUser)
if err != nil {
global.LOG.Error(err)
return
}
Id := strconv.Itoa(giteeUser.ID)
userSocial, err := userSocialService.QueryUserSocialByOpenIDService(Id, enum.OAuthSourceGitee)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
db := global.DB
tx := db.Begin() // 开始事务
if tx.Error != nil {
global.LOG.Error(tx.Error)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 第一次登录,创建用户
uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10)
user := model.ScaAuthUser{
UID: &uidStr,
Username: &giteeUser.Login,
Nickname: &giteeUser.Name,
Avatar: &giteeUser.AvatarURL,
Blog: &giteeUser.Blog,
Email: &giteeUser.Email,
Gender: &enum.Male,
}
addUser, err := userService.AddUserService(user)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
gitee := enum.OAuthSourceGitee
userSocial = model.ScaAuthUserSocial{
UserID: &uidStr,
OpenID: &Id,
Source: &gitee,
}
err = userSocialService.AddUserSocialService(userSocial)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
HandleLoginResponse(c, *addUser.UID)
} else {
HandleLoginResponse(c, *userSocial.UserID)
}
return return
} }
// 获取用户信息
userInfo, err := GetGiteeUserInfo(token)
if err != nil {
global.LOG.Error(err)
return
}
// 处理用户信息
userInfoBytes, err := json.Marshal(userInfo)
if err != nil {
global.LOG.Error(err)
return
}
var giteeUser GiteeUser
err = json.Unmarshal(userInfoBytes, &giteeUser)
if err != nil {
global.LOG.Error(err)
return
}
Id := strconv.Itoa(giteeUser.ID)
userSocial, err := userSocialService.QueryUserSocialByOpenIDService(Id, enum.OAuthSourceGitee)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
db := global.DB
tx := db.Begin() // 开始事务
if tx.Error != nil {
global.LOG.Error(tx.Error)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 第一次登录,创建用户
uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10)
user := model.ScaAuthUser{
UID: uidStr,
Username: giteeUser.Login,
Nickname: giteeUser.Name,
Avatar: giteeUser.AvatarURL,
Blog: giteeUser.Blog,
Email: giteeUser.Email,
Gender: enum.Male,
}
addUser, wrong := userService.AddUserService(user)
if wrong != nil {
tx.Rollback()
global.LOG.Error(wrong)
return
}
gitee := enum.OAuthSourceGitee
userSocial = model.ScaAuthUserSocial{
UserID: uidStr,
OpenID: Id,
Source: gitee,
}
err = userSocialService.AddUserSocialService(userSocial)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
if err = tx.Commit().Error; err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
HandleLoginResponse(c, addUser.UID)
} else {
HandleLoginResponse(c, userSocial.UserID)
}
} }

View File

@@ -141,124 +141,111 @@ func GetUserInfo(token *Token) (map[string]interface{}, error) {
// @Success 200 {string} string "登录成功" // @Success 200 {string} string "登录成功"
// @Router /controller/oauth/github/callback [get] // @Router /controller/oauth/github/callback [get]
func (OAuthController) Callback(c *gin.Context) { func (OAuthController) Callback(c *gin.Context) {
var err error
// 获取 code // 获取 code
var code = c.Query("code") code := c.Query("code")
if code == "" { if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
// 使用channel来接收异步操作的结果 // 获取 token
tokenChan := make(chan *Token) tokenAuthUrl := GetTokenAuthUrl(code)
userInfoChan := make(chan map[string]interface{}) token, err := GetToken(tokenAuthUrl)
errChan := make(chan error) if err != nil {
// 异步获取token
go func() {
var tokenAuthUrl = GetTokenAuthUrl(code)
token, err := GetToken(tokenAuthUrl)
if err != nil {
errChan <- err
return
}
tokenChan <- token
}()
// 异步获取用户信息
go func() {
token := <-tokenChan
if token == nil {
return
}
userInfo, err := GetUserInfo(token)
if err != nil {
errChan <- err
return
}
userInfoChan <- userInfo
}()
select {
case err = <-errChan:
global.LOG.Error(err) global.LOG.Error(err)
return return
case userInfo := <-userInfoChan: }
if userInfo == nil { if token == nil {
global.LOG.Error(<-errChan) global.LOG.Error(errors.New("failed to get token"))
return
}
// 继续处理用户信息
userInfoBytes, err := json.Marshal(<-userInfoChan)
if err != nil {
global.LOG.Error(err)
return
}
var gitHubUser GitHubUser
err = json.Unmarshal(userInfoBytes, &gitHubUser)
if err != nil {
global.LOG.Error(err)
return
}
Id := strconv.Itoa(gitHubUser.ID)
userSocial, err := userSocialService.QueryUserSocialByOpenIDService(Id, enum.OAuthSourceGithub)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
db := global.DB
tx := db.Begin() // 开始事务
if tx.Error != nil {
global.LOG.Error(tx.Error)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 第一次登录,创建用户
uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10)
user := model.ScaAuthUser{
UID: &uidStr,
Username: &gitHubUser.Login,
Nickname: &gitHubUser.Name,
Avatar: &gitHubUser.AvatarURL,
Blog: &gitHubUser.Blog,
Email: &gitHubUser.Email,
Gender: &enum.Male,
}
addUser, err := userService.AddUserService(user)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
github := enum.OAuthSourceGithub
userSocial = model.ScaAuthUserSocial{
UserID: &uidStr,
OpenID: &Id,
Source: &github,
}
err = userSocialService.AddUserSocialService(userSocial)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
HandleLoginResponse(c, *addUser.UID)
} else {
HandleLoginResponse(c, *userSocial.UserID)
}
return return
} }
// 获取用户信息
userInfo, err := GetUserInfo(token)
if err != nil {
global.LOG.Error(err)
return
}
if userInfo == nil {
global.LOG.Error(errors.New("failed to get user info"))
return
}
// 处理用户信息
userInfoBytes, err := json.Marshal(userInfo)
if err != nil {
global.LOG.Error(err)
return
}
var gitHubUser GitHubUser
err = json.Unmarshal(userInfoBytes, &gitHubUser)
if err != nil {
global.LOG.Error(err)
return
}
Id := strconv.Itoa(gitHubUser.ID)
userSocial, err := userSocialService.QueryUserSocialByOpenIDService(Id, enum.OAuthSourceGithub)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
db := global.DB
tx := db.Begin() // 开始事务
if tx.Error != nil {
global.LOG.Error(tx.Error)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 第一次登录,创建用户
uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10)
user := model.ScaAuthUser{
UID: uidStr,
Username: gitHubUser.Login,
Nickname: gitHubUser.Name,
Avatar: gitHubUser.AvatarURL,
Blog: gitHubUser.Blog,
Email: gitHubUser.Email,
Gender: enum.Male,
}
addUser, wrong := userService.AddUserService(user)
if wrong != nil {
tx.Rollback()
global.LOG.Error(wrong)
return
}
github := enum.OAuthSourceGithub
userSocial = model.ScaAuthUserSocial{
UserID: uidStr,
OpenID: Id,
Source: github,
}
err = userSocialService.AddUserSocialService(userSocial)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
if err = tx.Commit().Error; err != nil {
tx.Rollback()
global.LOG.Error(err)
return
}
HandleLoginResponse(c, addUser.UID)
} else {
HandleLoginResponse(c, userSocial.UserID)
}
} }

View File

@@ -11,6 +11,7 @@ import (
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
"schisandra-cloud-album/service/impl" "schisandra-cloud-album/service/impl"
"schisandra-cloud-album/utils" "schisandra-cloud-album/utils"
"sync"
"time" "time"
) )
@@ -31,12 +32,73 @@ var script = `
` `
func HandleLoginResponse(c *gin.Context, uid string) { func HandleLoginResponse(c *gin.Context, uid string) {
res, data := HandelUserLogin(uid, c) // 查询用户信息
if !res { user := userService.QueryUserByUuidService(&uid)
var accessToken, refreshToken string
var expiresAt int64
var err error
var wg sync.WaitGroup
var accessTokenErr error
wg.Add(2) // 增加计数器,等待两个协程完成
// 使用goroutine生成accessToken
go func() {
defer wg.Done() // 完成时减少计数器
accessToken, accessTokenErr = utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: &uid})
}()
// 使用goroutine生成refreshToken
go func() {
defer wg.Done() // 完成时减少计数器
refreshToken, expiresAt = utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: &uid}, time.Hour*24*7)
}()
// 等待两个协程完成
wg.Wait()
// 检查生成accessToken时是否有错误
if accessTokenErr != nil {
global.LOG.Error(accessTokenErr)
return return
} }
tokenData, err := json.Marshal(data) data := ResponseData{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresAt: expiresAt,
UID: &uid,
UserInfo: UserInfo{
Username: user.Username,
Nickname: user.Nickname,
Avatar: user.Avatar,
Email: user.Email,
Phone: user.Phone,
Gender: user.Gender,
Status: user.Status,
CreateAt: *user.CreatedTime,
},
}
if err = utils.SetSession(c, constant.SessionKey, data); err != nil {
return
}
// 将数据存入redis
if err = redis.Set(constant.UserLoginTokenRedisKey+uid, data, time.Hour*24*7).Err(); err != nil {
global.LOG.Error(err)
return
}
responseData := result.Response{
Data: data,
Message: "success",
Code: 200,
Success: true,
}
tokenData, err := json.Marshal(responseData)
if err != nil { if err != nil {
global.LOG.Error(err) global.LOG.Error(err)
return return
@@ -46,78 +108,3 @@ func HandleLoginResponse(c *gin.Context, uid string) {
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript)) c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
return return
} }
// HandelUserLogin 处理用户登录
func HandelUserLogin(userId string, c *gin.Context) (bool, result.Response) {
// 使用goroutine生成accessToken
accessTokenChan := make(chan string)
errChan := make(chan error)
go func() {
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: &userId})
if err != nil {
errChan <- err
return
}
accessTokenChan <- accessToken
}()
// 使用goroutine生成refreshToken
refreshTokenChan := make(chan string)
expiresAtChan := make(chan int64)
go func() {
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: &userId}, time.Hour*24*7)
refreshTokenChan <- refreshToken
expiresAtChan <- expiresAt
}()
// 等待accessToken和refreshToken生成完成
var accessToken string
var refreshToken string
var expiresAt int64
var err error
select {
case accessToken = <-accessTokenChan:
case err = <-errChan:
global.LOG.Error(err)
return false, result.Response{}
}
select {
case refreshToken = <-refreshTokenChan:
case expiresAt = <-expiresAtChan:
}
data := ResponseData{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresAt: expiresAt,
UID: &userId,
}
wrong := utils.SetSession(c, constant.SessionKey, data)
if wrong != nil {
return false, result.Response{}
}
// 使用goroutine将数据存入redis
redisErrChan := make(chan error)
go func() {
fail := redis.Set(constant.UserLoginTokenRedisKey+userId, data, time.Hour*24*7).Err()
if fail != nil {
redisErrChan <- fail
return
}
redisErrChan <- nil
}()
// 等待redis操作完成
redisErr := <-redisErrChan
if redisErr != nil {
global.LOG.Error(redisErr)
return false, result.Response{}
}
responseData := result.Response{
Data: data,
Message: "success",
Code: 200,
Success: true,
}
return true, responseData
}

View File

@@ -166,72 +166,40 @@ func GetQQUserUserInfo(token *QQToken, openId string) (map[string]interface{}, e
// @Produce json // @Produce json
// @Router /controller/oauth/qq/callback [get] // @Router /controller/oauth/qq/callback [get]
func (OAuthController) QQCallback(c *gin.Context) { func (OAuthController) QQCallback(c *gin.Context) {
var err error
// 获取 code // 获取 code
var code = c.Query("code") code := c.Query("code")
if code == "" { if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
// 通过 code, 获取 token // 通过 code 获取 token
var tokenAuthUrl = GetQQTokenAuthUrl(code) tokenAuthUrl := GetQQTokenAuthUrl(code)
tokenChan := make(chan *QQToken) token, err := GetQQToken(tokenAuthUrl)
errChan := make(chan error) if err != nil {
go func() { global.LOG.Error(err)
token, err := GetQQToken(tokenAuthUrl) return
if err != nil { }
errChan <- err if token == nil {
return global.LOG.Error(errors.New("failed to get token"))
} return
tokenChan <- token }
}()
var token *QQToken // 通过 token 获取 openid
select { authQQme, err := GetQQUserOpenID(token)
case token = <-tokenChan: if err != nil {
case err = <-errChan:
global.LOG.Error(err) global.LOG.Error(err)
return return
} }
// 通过 token,获取 openid // 通过 token openid 获取用户信息
openIDChan := make(chan *AuthQQme) userInfo, err := GetQQUserUserInfo(token, authQQme.OpenID)
errChan = make(chan error) if err != nil {
go func() {
authQQme, err := GetQQUserOpenID(token)
if err != nil {
errChan <- err
return
}
openIDChan <- authQQme
}()
var authQQme *AuthQQme
select {
case authQQme = <-openIDChan:
case err = <-errChan:
global.LOG.Error(err)
return
}
// 通过token获取用户信息
userInfoChan := make(chan map[string]interface{})
errChan = make(chan error)
go func() {
userInfo, err := GetQQUserUserInfo(token, authQQme.OpenID)
if err != nil {
errChan <- err
return
}
userInfoChan <- userInfo
}()
var userInfo map[string]interface{}
select {
case userInfo = <-userInfoChan:
case err = <-errChan:
global.LOG.Error(err) global.LOG.Error(err)
return return
} }
// 处理用户信息
userInfoBytes, err := json.Marshal(userInfo) userInfoBytes, err := json.Marshal(userInfo)
if err != nil { if err != nil {
global.LOG.Error(err) global.LOG.Error(err)
@@ -244,6 +212,7 @@ func (OAuthController) QQCallback(c *gin.Context) {
return return
} }
// 查询用户社交信息
userSocial, err := userSocialService.QueryUserSocialByOpenIDService(authQQme.OpenID, enum.OAuthSourceQQ) userSocial, err := userSocialService.QueryUserSocialByOpenIDService(authQQme.OpenID, enum.OAuthSourceQQ)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
db := global.DB db := global.DB
@@ -257,27 +226,29 @@ func (OAuthController) QQCallback(c *gin.Context) {
tx.Rollback() tx.Rollback()
} }
}() }()
// 第一次登录,创建用户 // 第一次登录,创建用户
uid := idgen.NextId() uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10) uidStr := strconv.FormatInt(uid, 10)
user := model.ScaAuthUser{ user := model.ScaAuthUser{
UID: &uidStr, UID: uidStr,
Username: &authQQme.OpenID, Username: authQQme.OpenID,
Nickname: &qqUserInfo.Nickname, Nickname: qqUserInfo.Nickname,
Avatar: &qqUserInfo.FigureurlQq1, Avatar: qqUserInfo.FigureurlQq1,
Gender: &qqUserInfo.Gender, Gender: qqUserInfo.Gender,
} }
addUser, err := userService.AddUserService(user) addUser, wrong := userService.AddUserService(user)
if err != nil { if wrong != nil {
tx.Rollback() tx.Rollback()
global.LOG.Error(err) global.LOG.Error(wrong)
return return
} }
qq := enum.OAuthSourceQQ qq := enum.OAuthSourceQQ
userSocial = model.ScaAuthUserSocial{ userSocial = model.ScaAuthUserSocial{
UserID: &uidStr, UserID: uidStr,
OpenID: &authQQme.OpenID, OpenID: authQQme.OpenID,
Source: &qq, Source: qq,
} }
err = userSocialService.AddUserSocialService(userSocial) err = userSocialService.AddUserSocialService(userSocial)
if err != nil { if err != nil {
@@ -285,20 +256,22 @@ func (OAuthController) QQCallback(c *gin.Context) {
global.LOG.Error(err) global.LOG.Error(err)
return return
} }
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User) _, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
global.LOG.Error(err) global.LOG.Error(err)
return return
} }
if err := tx.Commit().Error; err != nil {
if err = tx.Commit().Error; err != nil {
tx.Rollback() tx.Rollback()
global.LOG.Error(err) global.LOG.Error(err)
return return
} }
HandleLoginResponse(c, *addUser.UID) HandleLoginResponse(c, addUser.UID)
return return
} else { } else {
HandleLoginResponse(c, *userSocial.UserID) HandleLoginResponse(c, userSocial.UserID)
} }
} }

View File

@@ -1,13 +1,27 @@
package oauth_controller package oauth_controller
import "encoding/json" import (
"encoding/json"
"time"
)
// ResponseData 返回数据 // ResponseData 返回数据
type ResponseData struct { type ResponseData struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
ExpiresAt int64 `json:"expires_at"` ExpiresAt int64 `json:"expires_at"`
UID *string `json:"uid"` UID *string `json:"uid"`
UserInfo UserInfo `json:"user_info"`
}
type UserInfo struct {
Username string `json:"username,omitempty"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
Gender string `json:"gender"`
Status int64 `json:"status"`
CreateAt time.Time `json:"create_at"`
} }
func (res ResponseData) MarshalBinary() ([]byte, error) { func (res ResponseData) MarshalBinary() ([]byte, error) {

View File

@@ -169,6 +169,7 @@ func wechatLoginHandler(openId string, clientId string, c *gin.Context) bool {
if openId == "" { if openId == "" {
return false return false
} }
authUserSocial, err := userSocialService.QueryUserSocialByOpenIDService(openId, enum.OAuthSourceWechat) authUserSocial, err := userSocialService.QueryUserSocialByOpenIDService(openId, enum.OAuthSourceWechat)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
tx := global.DB.Begin() tx := global.DB.Begin()
@@ -180,107 +181,63 @@ func wechatLoginHandler(openId string, clientId string, c *gin.Context) bool {
uid := idgen.NextId() uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10) uidStr := strconv.FormatInt(uid, 10)
avatar, err := utils.GenerateAvatar(uidStr) avatar := utils.GenerateAvatar(uidStr)
name := randomname.GenerateName() name := randomname.GenerateName()
if err != nil {
global.LOG.Errorln(err)
return false
}
createUser := model.ScaAuthUser{ createUser := model.ScaAuthUser{
UID: &uidStr, UID: uidStr,
Username: &openId, Username: openId,
Avatar: &avatar, Avatar: avatar,
Nickname: &name, Nickname: name,
Gender: &enum.Male, Gender: enum.Male,
} }
// 异步添加用户 // 添加用户
addUserChan := make(chan *model.ScaAuthUser, 1) addUser, worn := userService.AddUserService(createUser)
errChan := make(chan error, 1) if worn != nil {
go func() {
addUser, err := userService.AddUserService(createUser)
if err != nil {
errChan <- err
return
}
addUserChan <- addUser
}()
var addUser *model.ScaAuthUser
select {
case addUser = <-addUserChan:
case err := <-errChan:
tx.Rollback() tx.Rollback()
global.LOG.Error(err) global.LOG.Error(worn)
return false return false
} }
wechat := enum.OAuthSourceWechat wechat := enum.OAuthSourceWechat
userSocial := model.ScaAuthUserSocial{ userSocial := model.ScaAuthUserSocial{
UserID: &uidStr, UserID: uidStr,
OpenID: &openId, OpenID: openId,
Source: &wechat, Source: wechat,
} }
// 异步添加用户社交信息 // 添加用户社交信息
wrongChan := make(chan error, 1) if wrong := userSocialService.AddUserSocialService(userSocial); wrong != nil {
go func() { tx.Rollback()
wrong := userSocialService.AddUserSocialService(userSocial) global.LOG.Error(wrong)
wrongChan <- wrong return false
}()
select {
case wrong := <-wrongChan:
if wrong != nil {
tx.Rollback()
global.LOG.Error(wrong)
return false
}
} }
// 异步添加角色 // 添加角色
roleErrChan := make(chan error, 1) if _, err = global.Casbin.AddRoleForUser(uidStr, enum.User); err != nil {
go func() { tx.Rollback()
_, err := global.Casbin.AddRoleForUser(uidStr, enum.User) global.LOG.Error(err)
roleErrChan <- err return false
}()
select {
case err := <-roleErrChan:
if err != nil {
tx.Rollback()
global.LOG.Error(err)
return false
}
} }
// 异步处理用户登录 // 处理用户登录
resChan := make(chan bool, 1) if res := handelUserLogin(addUser.UID, clientId, c); !res {
go func() { tx.Rollback()
res := handelUserLogin(*addUser.UID, clientId, c) return false
resChan <- res
}()
select {
case res := <-resChan:
if !res {
tx.Rollback()
return false
}
} }
tx.Commit() tx.Commit()
return true return true
} else { } else {
res := handelUserLogin(*authUserSocial.UserID, clientId, c) res := handelUserLogin(authUserSocial.UserID, clientId, c)
if !res { return res
return false
}
return true
} }
} }
// handelUserLogin 处理用户登录 // handelUserLogin 处理用户登录
func handelUserLogin(userId string, clientId string, c *gin.Context) bool { func handelUserLogin(userId string, clientId string, c *gin.Context) bool {
user := userService.QueryUserByUuidService(&userId)
resultChan := make(chan bool, 1) resultChan := make(chan bool, 1)
go func() { go func() {
@@ -295,6 +252,16 @@ func handelUserLogin(userId string, clientId string, c *gin.Context) bool {
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
UID: &userId, UID: &userId,
UserInfo: UserInfo{
Username: user.Username,
Nickname: user.Nickname,
Avatar: user.Avatar,
Gender: user.Gender,
Phone: user.Phone,
Email: user.Email,
CreateAt: *user.CreatedTime,
Status: user.Status,
},
} }
fail := redis.Set(constant.UserLoginTokenRedisKey+userId, data, time.Hour*24*7).Err() fail := redis.Set(constant.UserLoginTokenRedisKey+userId, data, time.Hour*24*7).Err()
if fail != nil { if fail != nil {

View File

@@ -139,7 +139,7 @@ func (UserController) AccountLogin(c *gin.Context) {
return return
} }
if !utils.Verify(*user.Password, password) { if !utils.Verify(user.Password, password) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
return return
} }
@@ -171,101 +171,66 @@ func (UserController) PhoneLogin(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneErrorFormat"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneErrorFormat"), c)
return return
} }
// 获取验证码
code := redis.Get(constant.UserLoginSmsRedisKey + phone).Val()
if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
return
}
userChan := make(chan model.ScaAuthUser) if captcha != code {
go func() { result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
user := userService.QueryUserByPhoneService(phone) return
userChan <- user }
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}() }()
// 查询用户
user := <-userChan user := userService.QueryUserByPhoneService(phone)
close(userChan)
if user.ID == 0 { if user.ID == 0 {
// 未注册 // 未注册
codeChan := make(chan *string)
go func() {
code := redis.Get(constant.UserLoginSmsRedisKey + phone).Val()
codeChan <- &code
}()
code := <-codeChan
close(codeChan)
if code == nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
return
}
uid := idgen.NextId() uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10) uidStr := strconv.FormatInt(uid, 10)
avatar := utils.GenerateAvatar(uidStr)
avatar, err := utils.GenerateAvatar(uidStr)
if err != nil {
global.LOG.Errorln(err)
return
}
name := randomname.GenerateName() name := randomname.GenerateName()
createUser := model.ScaAuthUser{ createUser := model.ScaAuthUser{
UID: &uidStr, UID: uidStr,
Phone: &phone, Phone: phone,
Avatar: &avatar, Avatar: avatar,
Nickname: &name, Nickname: name,
Gender: &enum.Male, Gender: enum.Male,
} }
errChan := make(chan error) addUser, w := userService.AddUserService(createUser)
go func() { if w != nil {
err = global.DB.Transaction(func(tx *gorm.DB) error { tx.Rollback()
addUser, w := userService.AddUserService(createUser) return
if w != nil { }
return w _, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
}
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
if err != nil {
return err
}
data, res := userService.HandelUserLogin(*addUser, autoLogin, c)
if !res {
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
return errors.New("login failed")
}
result.OkWithData(data, c)
return nil
})
errChan <- err
}()
err = <-errChan
close(errChan)
if err != nil { if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "RegisterUserError"), c) tx.Rollback()
return return
} }
} else { data, res := userService.HandelUserLogin(*addUser, autoLogin, c)
codeChan := make(chan string)
go func() {
code := redis.Get(constant.UserLoginSmsRedisKey + phone).Val()
codeChan <- code
}()
code := <-codeChan
close(codeChan)
if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
return
}
if captcha != code {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
return
}
data, res := userService.HandelUserLogin(user, autoLogin, c)
if !res { if !res {
tx.Rollback()
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
return return
} }
tx.Commit()
result.OkWithData(data, c)
} else {
data, res := userService.HandelUserLogin(user, autoLogin, c)
if !res {
tx.Rollback()
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
return
}
tx.Commit()
result.OkWithData(data, c) result.OkWithData(data, c)
} }
} }
@@ -360,7 +325,7 @@ func (UserController) ResetPassword(c *gin.Context) {
return return
} }
if err := userService.UpdateUserService(phone, encrypt); err != nil { if err = userService.UpdateUserService(phone, encrypt); err != nil {
tx.Rollback() tx.Rollback()
result.FailWithMessage(ginI18n.MustGetMessage(c, "ResetPasswordError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ResetPasswordError"), c)
return return
@@ -430,36 +395,44 @@ func (UserController) GetUserLoginDevice(c *gin.Context) {
platform := ua.Platform() platform := ua.Platform()
engine, engineVersion := ua.Engine() engine, engineVersion := ua.Engine()
device := model.ScaAuthUserDevice{ device := model.ScaAuthUserDevice{
UserID: &userId, UserID: userId,
IP: &ip, IP: ip,
Location: &location, Location: location,
Agent: userAgent, Agent: userAgent,
Browser: &browser, Browser: browser,
BrowserVersion: &browserVersion, BrowserVersion: browserVersion,
OperatingSystem: &os, OperatingSystem: os,
Mobile: &mobile, Mobile: mobile,
Bot: &isBot, Bot: isBot,
Mozilla: &mozilla, Mozilla: mozilla,
Platform: &platform, Platform: platform,
EngineName: &engine, EngineName: engine,
EngineVersion: &engineVersion, EngineVersion: engineVersion,
} }
mu.Lock() tx := global.DB.Begin()
defer mu.Unlock() defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
userDevice, err := userDeviceService.GetUserDeviceByUIDIPAgentService(userId, ip, userAgent) userDevice, err := userDeviceService.GetUserDeviceByUIDIPAgentService(userId, ip, userAgent)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = userDeviceService.AddUserDeviceService(&device) err = userDeviceService.AddUserDeviceService(&device)
if err != nil { if err != nil {
tx.Rollback()
global.LOG.Errorln(err) global.LOG.Errorln(err)
return return
} }
tx.Commit()
return return
} else { } else {
err := userDeviceService.UpdateUserDeviceService(userDevice.ID, &device) err = userDeviceService.UpdateUserDeviceService(userDevice.ID, &device)
if err != nil { if err != nil {
tx.Rollback()
global.LOG.Errorln(err) global.LOG.Errorln(err)
return return
} }
tx.Commit()
return return
} }
} }

View File

@@ -59,13 +59,13 @@ func (UserDaoImpl) AddUser(user model.ScaAuthUser) (*model.ScaAuthUser, error) {
// UpdateUser 更新用户 // UpdateUser 更新用户
func (UserDaoImpl) UpdateUser(phone string, password string) error { func (UserDaoImpl) UpdateUser(phone string, password string) error {
return global.DB.Model(&model.ScaAuthUser{}).Where("phone = ? and deleted = 0", phone).Updates(&model.ScaAuthUser{Password: &password}).Error return global.DB.Model(&model.ScaAuthUser{}).Where("phone = ? and deleted = 0", phone).Updates(&model.ScaAuthUser{Password: password}).Error
} }
// DeleteUser 删除用户 // DeleteUser 删除用户
func (UserDaoImpl) DeleteUser(uuid string) error { func (UserDaoImpl) DeleteUser(uuid string) error {
authUser := model.ScaAuthUser{} authUser := model.ScaAuthUser{}
return global.DB.Model(&authUser).Where("uid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: &enum.DELETED}).Error return global.DB.Model(&authUser).Where("uid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: enum.DELETED}).Error
} }
// QueryUserByPhone 根据手机号查询用户 // QueryUserByPhone 根据手机号查询用户

View File

@@ -10,21 +10,21 @@ const TableNameScaAuthPermission = "sca_auth_permission"
// ScaAuthPermission 权限表 // ScaAuthPermission 权限表
type ScaAuthPermission struct { type ScaAuthPermission struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
PermissionName *string `gorm:"column:permission_name;type:varchar(64);comment:权限名称" json:"permission_name"` // 权限名称 PermissionName string `gorm:"column:permission_name;type:varchar(64);comment:权限名称" json:"permission_name"` // 权限名称
ParentID *int64 `gorm:"column:parent_id;type:bigint(20);comment:父ID" json:"parent_id"` // 父ID ParentID int64 `gorm:"column:parent_id;type:bigint(20);comment:父ID" json:"parent_id"` // 父ID
Type *int64 `gorm:"column:type;type:tinyint(4);comment:类型 0 菜单 1 接口" json:"type"` // 类型 0 菜单 1 目录 2 按钮 -1其他 Type int64 `gorm:"column:type;type:tinyint(4);comment:类型 0 菜单 1 接口" json:"type"` // 类型 0 菜单 1 目录 2 按钮 -1其他
Path *string `gorm:"column:path;type:varchar(30);comment:路径" json:"path"` // 路径 Path string `gorm:"column:path;type:varchar(30);comment:路径" json:"path"` // 路径
Status *int64 `gorm:"column:status;type:tinyint(4);comment:状态 0 启用 1 停用" json:"status"` // 状态 0 启用 1 停用 Status int64 `gorm:"column:status;type:tinyint(4);comment:状态 0 启用 1 停用" json:"status"` // 状态 0 启用 1 停用
Method *string `gorm:"column:method;type:varchar(20);comment:请求方式" json:"method"` // 请求方式 Method string `gorm:"column:method;type:varchar(20);comment:请求方式" json:"method"` // 请求方式
Icon *string `gorm:"column:icon;type:varchar(128);comment:图标" json:"icon"` // 图标 Icon string `gorm:"column:icon;type:varchar(128);comment:图标" json:"icon"` // 图标
PermissionKey *string `gorm:"column:permission_key;type:varchar(64);comment:权限关键字" json:"permission_key"` // 权限关键字 PermissionKey string `gorm:"column:permission_key;type:varchar(64);comment:权限关键字" json:"permission_key"` // 权限关键字
Order *int64 `gorm:"column:order;type:int(11);comment:排序" json:"order"` // 排序 Order int64 `gorm:"column:order;type:int(11);comment:排序" json:"order"` // 排序
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间 CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间 UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
Deleted *int64 `gorm:"column:deleted;type:int(11);comment:是否删除" json:"deleted"` // 是否删除 Deleted int64 `gorm:"column:deleted;type:int(11);comment:是否删除" json:"deleted"` // 是否删除
Remark *string `gorm:"column:remark;type:varchar(255);comment:备注 描述" json:"remark"` // 备注 描述 Remark string `gorm:"column:remark;type:varchar(255);comment:备注 描述" json:"remark"` // 备注 描述
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人 CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"`
} }
// TableName ScaAuthPermission's table name // TableName ScaAuthPermission's table name

View File

@@ -14,9 +14,9 @@ type ScaAuthRole struct {
RoleKey string `gorm:"column:role_key;type:varchar(64);not null;comment:角色关键字" json:"role_key"` // 角色关键字 RoleKey string `gorm:"column:role_key;type:varchar(64);not null;comment:角色关键字" json:"role_key"` // 角色关键字
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间 CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间 UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
Deleted *int64 `gorm:"column:deleted;type:int(11);comment:是否删除 0 未删除 1已删除" json:"deleted"` // 是否删除 0 未删除 1已删除 Deleted int64 `gorm:"column:deleted;type:int(11);comment:是否删除 0 未删除 1已删除" json:"deleted"` // 是否删除 0 未删除 1已删除
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人 CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"`
} }
// TableName ScaAuthRole's table name // TableName ScaAuthRole's table name

View File

@@ -10,24 +10,24 @@ const TableNameScaAuthUser = "sca_auth_user"
// ScaAuthUser 用户表 // ScaAuthUser 用户表
type ScaAuthUser struct { type ScaAuthUser struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:自增ID" json:"-"` // 自增ID ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:自增ID" json:"-"` // 自增ID
UID *string `gorm:"column:uid;type:varchar(20);comment:唯一ID" json:"uid"` // 唯一ID UID string `gorm:"column:uid;type:varchar(20);comment:唯一ID" json:"uid"` // 唯一ID
Username *string `gorm:"column:username;type:varchar(32);comment:用户名" json:"username"` // 用户名 Username string `gorm:"column:username;type:varchar(32);comment:用户名" json:"username"` // 用户名
Nickname *string `gorm:"column:nickname;type:varchar(32);comment:昵称" json:"nickname"` // 昵称 Nickname string `gorm:"column:nickname;type:varchar(32);comment:昵称" json:"nickname"` // 昵称
Email *string `gorm:"column:email;type:varchar(32);comment:邮箱" json:"email"` // 邮箱 Email string `gorm:"column:email;type:varchar(32);comment:邮箱" json:"email"` // 邮箱
Phone *string `gorm:"column:phone;type:varchar(32);comment:电话" json:"phone"` // 电话 Phone string `gorm:"column:phone;type:varchar(32);comment:电话" json:"phone"` // 电话
Password *string `gorm:"column:password;type:varchar(64);comment:密码" json:"-"` // 密码 Password string `gorm:"column:password;type:varchar(64);comment:密码" json:"-"` // 密码
Gender *string `gorm:"column:gender;type:varchar(32);comment:性别" json:"gender"` // 性别 Gender string `gorm:"column:gender;type:varchar(32);comment:性别" json:"gender"` // 性别
Avatar *string `gorm:"column:avatar;type:longtext;comment:头像" json:"avatar"` // 头像 Avatar string `gorm:"column:avatar;type:longtext;comment:头像" json:"avatar"` // 头像
Status *int64 `gorm:"column:status;type:tinyint(4);default:0;comment:状态 0 正常 1 封禁" json:"status"` // 状态 0 正常 1 封禁 Status int64 `gorm:"column:status;type:tinyint(4);default:0;comment:状态 0 正常 1 封禁" json:"status"` // 状态 0 正常 1 封禁
Introduce *string `gorm:"column:introduce;type:varchar(255);comment:介绍" json:"introduce"` // 介绍 Introduce string `gorm:"column:introduce;type:varchar(255);comment:介绍" json:"introduce"` // 介绍
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间 CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间 UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
Deleted *int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0 未删除 1 已删除" json:"-"` // 是否删除 0 未删除 1 已删除 Deleted int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0 未删除 1 已删除" json:"-"` // 是否删除 0 未删除 1 已删除
Blog *string `gorm:"column:blog;type:varchar(30);comment:博客" json:"blog"` // 博客 Blog string `gorm:"column:blog;type:varchar(30);comment:博客" json:"blog"` // 博客
Location *string `gorm:"column:location;type:varchar(50);comment:地址" json:"location"` // 地址 Location string `gorm:"column:location;type:varchar(50);comment:地址" json:"location"` // 地址
Company *string `gorm:"column:company;type:varchar(50);comment:公司" json:"company"` // 公司 Company string `gorm:"column:company;type:varchar(50);comment:公司" json:"company"` // 公司
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人 CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` // 更新人 UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` // 更新人
} }
// TableName ScaAuthUser's table name // TableName ScaAuthUser's table name

View File

@@ -9,24 +9,24 @@ const TableNameScaAuthUserDevice = "sca_auth_user_device"
// ScaAuthUserDevice 用户设备信息 // ScaAuthUserDevice 用户设备信息
type ScaAuthUserDevice struct { type ScaAuthUserDevice struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
UserID *string `gorm:"column:user_id;type:varchar(20);comment:用户ID" json:"user_id"` // 用户ID UserID string `gorm:"column:user_id;type:varchar(20);comment:用户ID" json:"user_id"` // 用户ID
IP *string `gorm:"column:ip;type:varchar(20);comment:登录IP" json:"ip"` // 登录IP IP string `gorm:"column:ip;type:varchar(20);comment:登录IP" json:"ip"` // 登录IP
Location *string `gorm:"column:location;type:varchar(20);comment:地址" json:"location"` // 地址 Location string `gorm:"column:location;type:varchar(20);comment:地址" json:"location"` // 地址
Agent string `gorm:"column:agent;type:varchar(255);comment:设备信息" json:"agent"` // 设备信息 Agent string `gorm:"column:agent;type:varchar(255);comment:设备信息" json:"agent"` // 设备信息
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间 CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间 UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
Deleted *int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除" json:"deleted"` // 是否删除 Deleted int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除" json:"deleted"` // 是否删除
Browser *string `gorm:"column:browser;type:varchar(20);comment:浏览器" json:"browser"` // 浏览器 Browser string `gorm:"column:browser;type:varchar(20);comment:浏览器" json:"browser"` // 浏览器
OperatingSystem *string `gorm:"column:operating_system;type:varchar(20);comment:操作系统" json:"operating_system"` // 操作系统 OperatingSystem string `gorm:"column:operating_system;type:varchar(20);comment:操作系统" json:"operating_system"` // 操作系统
BrowserVersion *string `gorm:"column:browser_version;type:varchar(20);comment:浏览器版本" json:"browser_version"` // 浏览器版本 BrowserVersion string `gorm:"column:browser_version;type:varchar(20);comment:浏览器版本" json:"browser_version"` // 浏览器版本
Mobile *bool `gorm:"column:mobile;type:int(11);comment:是否为手机" json:"mobile"` // 是否为手机 Mobile bool `gorm:"column:mobile;type:int(11);comment:是否为手机" json:"mobile"` // 是否为手机
Bot *bool `gorm:"column:bot;type:int(11);comment:是否为机器人" json:"bot"` // 是否为机器人 Bot bool `gorm:"column:bot;type:int(11);comment:是否为机器人" json:"bot"` // 是否为机器人
Mozilla *string `gorm:"column:mozilla;type:varchar(10);comment:火狐版本" json:"mozilla"` // 火狐版本 Mozilla string `gorm:"column:mozilla;type:varchar(10);comment:火狐版本" json:"mozilla"` // 火狐版本
Platform *string `gorm:"column:platform;type:varchar(20);comment:平台" json:"platform"` // 平台 Platform string `gorm:"column:platform;type:varchar(20);comment:平台" json:"platform"` // 平台
EngineName *string `gorm:"column:engine_name;type:varchar(20);comment:引擎名称" json:"engine_name"` // 引擎名称 EngineName string `gorm:"column:engine_name;type:varchar(20);comment:引擎名称" json:"engine_name"` // 引擎名称
EngineVersion *string `gorm:"column:engine_version;type:varchar(20);comment:引擎版本" json:"engine_version"` // 引擎版本 EngineVersion string `gorm:"column:engine_version;type:varchar(20);comment:引擎版本" json:"engine_version"` // 引擎版本
CreatedBy *string `gorm:"column:created_by;type:varchar(32);default:system;comment:创建人" json:"created_by"` // 创建人 CreatedBy string `gorm:"column:created_by;type:varchar(32);default:system;comment:创建人" json:"created_by"` // 创建人
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"`
} }
// TableName ScaAuthUserDevice's table name // TableName ScaAuthUserDevice's table name

View File

@@ -9,15 +9,15 @@ const TableNameScaAuthUserSocial = "sca_auth_user_social"
// ScaAuthUserSocial 社会用户信息表 // ScaAuthUserSocial 社会用户信息表
type ScaAuthUserSocial struct { type ScaAuthUserSocial struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
UserID *string `gorm:"column:user_id;type:varchar(20);not null;comment:用户ID" json:"user_id"` // 用户ID UserID string `gorm:"column:user_id;type:varchar(20);not null;comment:用户ID" json:"user_id"` // 用户ID
Source *string `gorm:"column:source;type:varchar(10);comment:第三方用户来源" json:"source"` // 第三方用户来源 Source string `gorm:"column:source;type:varchar(10);comment:第三方用户来源" json:"source"` // 第三方用户来源
OpenID *string `gorm:"column:open_id;type:varchar(50);comment:第三方用户的 open id" json:"open_id"` // 第三方用户的 open id OpenID string `gorm:"column:open_id;type:varchar(50);comment:第三方用户的 open id" json:"open_id"` // 第三方用户的 open id
Status *int64 `gorm:"column:status;type:int(11);default:0;comment:状态 0正常 1 封禁" json:"status"` // 状态 0正常 1 封禁 Status int64 `gorm:"column:status;type:int(11);default:0;comment:状态 0正常 1 封禁" json:"status"` // 状态 0正常 1 封禁
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间 CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间 UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
Deleted *int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除" json:"deleted"` // 是否删除 Deleted int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除" json:"deleted"` // 是否删除
CreatedBy *string `gorm:"column:created_by;type:varchar(32);default:system;comment:创建人" json:"created_by"` // 创建人 CreatedBy string `gorm:"column:created_by;type:varchar(32);default:system;comment:创建人" json:"created_by"` // 创建人
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"`
} }
// TableName ScaAuthUserSocial's table name // TableName ScaAuthUserSocial's table name

View File

@@ -200,8 +200,8 @@ func (CommentReplyServiceImpl) GetCommentReplyListService(uid string, topicId st
return return
} }
for _, userInfo := range userInfos { for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo userInfoMap[userInfo.UID] = *userInfo
redis.Set(constant.CommentUserListRedisKey+*userInfo.UID, userInfo, 24*time.Hour) redis.Set(constant.CommentUserListRedisKey+userInfo.UID, userInfo, 24*time.Hour)
} }
} }
}() }()
@@ -279,13 +279,13 @@ func (CommentReplyServiceImpl) GetCommentReplyListService(uid string, topicId st
return return
} }
commentContent := CommentContent{ commentContent := CommentContent{
Avatar: *userInfo.Avatar, Avatar: userInfo.Avatar,
NickName: *userInfo.Nickname, NickName: userInfo.Nickname,
Id: reply.Id, Id: reply.Id,
UserId: reply.UserId, UserId: reply.UserId,
TopicId: reply.TopicId, TopicId: reply.TopicId,
Content: reply.Content, Content: reply.Content,
ReplyUsername: *replyUserInfo.Nickname, ReplyUsername: replyUserInfo.Nickname,
ReplyCount: reply.ReplyCount, ReplyCount: reply.ReplyCount,
Likes: reply.Likes, Likes: reply.Likes,
CreatedTime: reply.CreatedTime, CreatedTime: reply.CreatedTime,
@@ -385,8 +385,8 @@ func (CommentReplyServiceImpl) GetCommentListService(uid string, topicId string,
return return
} }
for _, userInfo := range userInfos { for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo userInfoMap[userInfo.UID] = *userInfo
redis.Set(constant.CommentUserListRedisKey+*userInfo.UID, userInfo, 24*time.Hour) redis.Set(constant.CommentUserListRedisKey+userInfo.UID, userInfo, 24*time.Hour)
} }
} }
}() }()
@@ -473,8 +473,8 @@ func (CommentReplyServiceImpl) GetCommentListService(uid string, topicId string,
return return
} }
commentContent := CommentContent{ commentContent := CommentContent{
Avatar: *userInfo.Avatar, Avatar: userInfo.Avatar,
NickName: *userInfo.Nickname, NickName: userInfo.Nickname,
Id: comment.Id, Id: comment.Id,
UserId: comment.UserId, UserId: comment.UserId,
TopicId: comment.TopicId, TopicId: comment.TopicId,

View File

@@ -25,10 +25,21 @@ var mu = &sync.Mutex{}
// ResponseData 返回数据 // ResponseData 返回数据
type ResponseData struct { type ResponseData struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
ExpiresAt int64 `json:"expires_at"` ExpiresAt int64 `json:"expires_at"`
UID *string `json:"uid"` UID *string `json:"uid"`
UserInfo UserInfo `json:"user_info"`
}
type UserInfo struct {
Username string `json:"username,omitempty"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
Gender string `json:"gender"`
Status int64 `json:"status"`
CreateAt time.Time `json:"create_at"`
} }
func (res ResponseData) MarshalBinary() ([]byte, error) { func (res ResponseData) MarshalBinary() ([]byte, error) {
@@ -115,13 +126,13 @@ func (UserServiceImpl) RefreshTokenService(refreshToken string) (*ResponseData,
// HandelUserLogin 处理用户登录 // HandelUserLogin 处理用户登录
func (UserServiceImpl) HandelUserLogin(user model.ScaAuthUser, autoLogin bool, c *gin.Context) (*ResponseData, bool) { func (UserServiceImpl) HandelUserLogin(user model.ScaAuthUser, autoLogin bool, c *gin.Context) (*ResponseData, bool) {
// 检查 user.UID 是否为 nil // 检查 user.UID 是否为 nil
if user.UID == nil { if user.UID == "" {
return nil, false return nil, false
} }
if !GetUserLoginDevice(user, c) { if !GetUserLoginDevice(user, c) {
return nil, false return nil, false
} }
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: user.UID}) accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: &user.UID})
if err != nil { if err != nil {
return nil, false return nil, false
} }
@@ -132,15 +143,25 @@ func (UserServiceImpl) HandelUserLogin(user model.ScaAuthUser, autoLogin bool, c
days = time.Minute * 30 days = time.Minute * 30
} }
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID}, days) refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: &user.UID}, days)
data := ResponseData{ data := ResponseData{
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
UID: user.UID, UID: &user.UID,
UserInfo: UserInfo{
Username: user.Username,
Nickname: user.Nickname,
Avatar: user.Avatar,
Phone: user.Phone,
Email: user.Email,
Gender: user.Gender,
Status: user.Status,
CreateAt: *user.CreatedTime,
},
} }
err = redis.Set(constant.UserLoginTokenRedisKey+*user.UID, data, days).Err() err = redis.Set(constant.UserLoginTokenRedisKey+user.UID, data, days).Err()
if err != nil { if err != nil {
return nil, false return nil, false
} }
@@ -156,7 +177,7 @@ func (UserServiceImpl) HandelUserLogin(user model.ScaAuthUser, autoLogin bool, c
func GetUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool { func GetUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool {
// 检查user.UID是否为空 // 检查user.UID是否为空
if user.UID == nil { if user.UID == "" {
global.LOG.Errorln("user.UID is nil") global.LOG.Errorln("user.UID is nil")
return false return false
} }
@@ -185,24 +206,24 @@ func GetUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool {
device := model.ScaAuthUserDevice{ device := model.ScaAuthUserDevice{
UserID: user.UID, UserID: user.UID,
IP: &ip, IP: ip,
Location: &location, Location: location,
Agent: userAgent, Agent: userAgent,
Browser: &browser, Browser: browser,
BrowserVersion: &browserVersion, BrowserVersion: browserVersion,
OperatingSystem: &os, OperatingSystem: os,
Mobile: &mobile, Mobile: mobile,
Bot: &isBot, Bot: isBot,
Mozilla: &mozilla, Mozilla: mozilla,
Platform: &platform, Platform: platform,
EngineName: &engine, EngineName: engine,
EngineVersion: &engineVersion, EngineVersion: engineVersion,
} }
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
userDevice, err := userDeviceDao.GetUserDeviceByUIDIPAgent(*user.UID, ip, userAgent) userDevice, err := userDeviceDao.GetUserDeviceByUIDIPAgent(user.UID, ip, userAgent)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = userDeviceDao.AddUserDevice(&device) err = userDeviceDao.AddUserDevice(&device)
if err != nil { if err != nil {

View File

@@ -1,9 +1,6 @@
package utils package utils
import ( import (
"encoding/base64"
"errors"
"io"
"net/http" "net/http"
"time" "time"
) )
@@ -14,41 +11,41 @@ var client = &http.Client{
} }
// GenerateAvatar 用于生成用户头像 // GenerateAvatar 用于生成用户头像
func GenerateAvatar(userId string) (baseImg string, err error) { func GenerateAvatar(userId string) (baseImg string) {
path := "https://api.multiavatar.com/" + userId + ".png" path := "https://api.multiavatar.com/" + userId + ".png"
// 创建请求 //// 创建请求
request, err := http.NewRequest("GET", path, nil) //request, err := http.NewRequest("GET", path, nil)
if err != nil { //if err != nil {
return "", errors.New("image request error") // return "", errors.New("image request error")
} //}
//
// 发送请求并获取响应 //// 发送请求并获取响应
respImg, err := client.Do(request) //respImg, err := client.Do(request)
if err != nil { //if err != nil {
return "", errors.New("failed to fetch image") // return "", errors.New("failed to fetch image")
} //}
defer func(Body io.ReadCloser) { //defer func(Body io.ReadCloser) {
err := Body.Close() // err := Body.Close()
if err != nil { // if err != nil {
return // return
} // }
}(respImg.Body) //}(respImg.Body)
//
// 读取图片数据 //// 读取图片数据
imgByte, err := io.ReadAll(respImg.Body) //imgByte, err := io.ReadAll(respImg.Body)
if err != nil { //if err != nil {
return "", errors.New("failed to read image data") // return "", errors.New("failed to read image data")
} //}
//
// 判断文件类型,生成一个前缀 //// 判断文件类型,生成一个前缀
mimeType := http.DetectContentType(imgByte) //mimeType := http.DetectContentType(imgByte)
switch mimeType { //switch mimeType {
case "image/png": //case "image/png":
baseImg = "data:image/png;base64," + base64.StdEncoding.EncodeToString(imgByte) // baseImg = "data:image/png;base64," + base64.StdEncoding.EncodeToString(imgByte)
default: //default:
return "", errors.New("unsupported image type") // return "", errors.New("unsupported image type")
} //}
return baseImg, nil return path
} }