♻️ refactored login-related code
This commit is contained in:
@@ -3,7 +3,8 @@ package user
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/rbcervilla/redisstore/v9"
|
||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||
"github.com/mssola/useragent"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -65,19 +66,20 @@ func (l *AccountLoginLogic) AccountLogin(w http.ResponseWriter, r *http.Request,
|
||||
if !utils.Verify(userInfo.Password, req.Password) {
|
||||
return response.ErrorWithI18n(l.ctx, "login.invalidPassword"), nil
|
||||
}
|
||||
data, err := HandleUserLogin(userInfo, l.svcCtx, req.AutoLogin, r, w, l.ctx)
|
||||
data, err := HandleLoginJWT(userInfo, l.svcCtx, req.AutoLogin, r, l.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 记录用户登录设备
|
||||
if err = GetUserLoginDevice(userInfo.UID, r, l.svcCtx.Ip2Region, l.svcCtx.DB); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.SuccessWithData(data), nil
|
||||
}
|
||||
|
||||
// HandleUserLogin 处理用户登录
|
||||
func HandleUserLogin(user *model.ScaAuthUser, svcCtx *svc.ServiceContext, autoLogin bool, r *http.Request, w http.ResponseWriter, ctx context.Context) (*types.LoginResponse, error) {
|
||||
// HandleLoginJWT 处理用户登录
|
||||
func HandleLoginJWT(user *model.ScaAuthUser, svcCtx *svc.ServiceContext, autoLogin bool, r *http.Request, ctx context.Context) (*types.LoginResponse, error) {
|
||||
// 获取用户登录设备
|
||||
err := GetUserLoginDevice(user.UID, r, svcCtx.Ip2Region, svcCtx.DB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 生成jwt token
|
||||
accessToken := jwt.GenerateAccessToken(svcCtx.Config.Auth.AccessSecret, jwt.AccessJWTPayload{
|
||||
UserID: user.UID,
|
||||
@@ -85,9 +87,9 @@ func HandleUserLogin(user *model.ScaAuthUser, svcCtx *svc.ServiceContext, autoLo
|
||||
})
|
||||
var days time.Duration
|
||||
if autoLogin {
|
||||
days = 7 * 24 * time.Hour
|
||||
days = 24 * time.Hour
|
||||
} else {
|
||||
days = time.Hour * 24
|
||||
days = time.Hour * 1
|
||||
}
|
||||
refreshToken := jwt.GenerateRefreshToken(svcCtx.Config.Auth.AccessSecret, jwt.RefreshJWTPayload{
|
||||
UserID: user.UID,
|
||||
@@ -106,29 +108,76 @@ func HandleUserLogin(user *model.ScaAuthUser, svcCtx *svc.ServiceContext, autoLo
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
UID: user.UID,
|
||||
Revoked: false,
|
||||
}
|
||||
err := svcCtx.RedisClient.Set(ctx, constant.UserTokenPrefix+user.UID, redisToken, days).Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = HandlerSession(r, w, user.UID, svcCtx.Session)
|
||||
err = svcCtx.RedisClient.Set(ctx, constant.UserTokenPrefix+user.UID, redisToken, days).Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &data, nil
|
||||
|
||||
}
|
||||
|
||||
// HandlerSession is a function to set the user_id in the session
|
||||
func HandlerSession(r *http.Request, w http.ResponseWriter, userID string, redisSession *redisstore.RedisStore) error {
|
||||
session, err := redisSession.Get(r, constant.SESSION_KEY)
|
||||
// GetUserLoginDevice 获取用户登录设备
|
||||
func GetUserLoginDevice(userId string, r *http.Request, ip2location *xdb.Searcher, DB *query.Query) error {
|
||||
userAgent := r.UserAgent()
|
||||
if userAgent == "" {
|
||||
return errors.New("user agent not found")
|
||||
}
|
||||
ip := utils.GetClientIP(r)
|
||||
location, err := ip2location.SearchByStr(ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Values["user_id"] = userID
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
location = utils.RemoveZeroAndAdjust(location)
|
||||
|
||||
ua := useragent.New(userAgent)
|
||||
isBot := ua.Bot()
|
||||
browser, browserVersion := ua.Browser()
|
||||
os := ua.OS()
|
||||
mobile := ua.Mobile()
|
||||
mozilla := ua.Mozilla()
|
||||
platform := ua.Platform()
|
||||
engine, engineVersion := ua.Engine()
|
||||
var newIsBot int64 = 0
|
||||
var newIsMobile int64 = 0
|
||||
if isBot {
|
||||
newIsBot = 1
|
||||
}
|
||||
if mobile {
|
||||
newIsMobile = 1
|
||||
}
|
||||
userDevice := DB.ScaAuthUserDevice
|
||||
device, err := userDevice.Where(userDevice.UserID.Eq(userId), userDevice.IP.Eq(ip), userDevice.Agent.Eq(userAgent)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
newDevice := &model.ScaAuthUserDevice{
|
||||
UserID: userId,
|
||||
Bot: newIsBot,
|
||||
Agent: userAgent,
|
||||
Browser: browser,
|
||||
BrowserVersion: browserVersion,
|
||||
EngineName: engine,
|
||||
EngineVersion: engineVersion,
|
||||
IP: ip,
|
||||
Location: location,
|
||||
OperatingSystem: os,
|
||||
Mobile: newIsMobile,
|
||||
Mozilla: mozilla,
|
||||
Platform: platform,
|
||||
}
|
||||
if device == nil {
|
||||
// 创建新的设备记录
|
||||
err = DB.ScaAuthUserDevice.Create(newDevice)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
resultInfo, err := userDevice.Where(userDevice.ID.Eq(device.ID)).Updates(newDevice)
|
||||
if err != nil || resultInfo.RowsAffected == 0 {
|
||||
return errors.New("update device failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@@ -1,115 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||
"github.com/mssola/useragent"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/jwt"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/response"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/utils"
|
||||
"schisandra-album-cloud-microservices/app/core/api/repository/mysql/model"
|
||||
"schisandra-album-cloud-microservices/app/core/api/repository/mysql/query"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetUserDeviceLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetUserDeviceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserDeviceLogic {
|
||||
return &GetUserDeviceLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetUserDeviceLogic) GetUserDevice(r *http.Request, w http.ResponseWriter, req *types.UserDeviceRequest) (resp *types.Response, err error) {
|
||||
token, ok := jwt.ParseAccessToken(l.svcCtx.Config.Auth.AccessSecret, req.AccessToken)
|
||||
if !ok {
|
||||
return response.Error(), nil
|
||||
}
|
||||
err = HandlerSession(r, w, token.UserID, l.svcCtx.Session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = GetUserLoginDevice(token.UserID, r, l.svcCtx.Ip2Region, l.svcCtx.DB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Success(), nil
|
||||
}
|
||||
|
||||
// GetUserLoginDevice 获取用户登录设备
|
||||
func GetUserLoginDevice(userId string, r *http.Request, ip2location *xdb.Searcher, DB *query.Query) error {
|
||||
userAgent := r.Header.Get("User-Agent")
|
||||
if userAgent == "" {
|
||||
return errors.New("user agent not found")
|
||||
}
|
||||
ip := utils.GetClientIP(r)
|
||||
location, err := ip2location.SearchByStr(ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
location = utils.RemoveZeroAndAdjust(location)
|
||||
|
||||
ua := useragent.New(userAgent)
|
||||
isBot := ua.Bot()
|
||||
browser, browserVersion := ua.Browser()
|
||||
os := ua.OS()
|
||||
mobile := ua.Mobile()
|
||||
mozilla := ua.Mozilla()
|
||||
platform := ua.Platform()
|
||||
engine, engineVersion := ua.Engine()
|
||||
var newIsBot int64 = 0
|
||||
var newIsMobile int64 = 0
|
||||
if isBot {
|
||||
newIsBot = 1
|
||||
}
|
||||
if mobile {
|
||||
newIsMobile = 1
|
||||
}
|
||||
userDevice := DB.ScaAuthUserDevice
|
||||
device, err := userDevice.Where(userDevice.UserID.Eq(userId), userDevice.IP.Eq(ip), userDevice.Agent.Eq(userAgent)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
newDevice := &model.ScaAuthUserDevice{
|
||||
UserID: userId,
|
||||
Bot: newIsBot,
|
||||
Agent: userAgent,
|
||||
Browser: browser,
|
||||
BrowserVersion: browserVersion,
|
||||
EngineName: engine,
|
||||
EngineVersion: engineVersion,
|
||||
IP: ip,
|
||||
Location: location,
|
||||
OperatingSystem: os,
|
||||
Mobile: newIsMobile,
|
||||
Mozilla: mozilla,
|
||||
Platform: platform,
|
||||
}
|
||||
if device == nil {
|
||||
// 创建新的设备记录
|
||||
err = DB.ScaAuthUserDevice.Create(newDevice)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
resultInfo, err := userDevice.Where(userDevice.ID.Eq(device.ID)).Updates(newDevice)
|
||||
if err != nil || resultInfo.RowsAffected == 0 {
|
||||
return errors.New("update device failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/basicService/qrCode/response"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/constant"
|
||||
response2 "schisandra-album-cloud-microservices/app/core/api/common/response"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/utils"
|
||||
"time"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetWechatOffiaccountQrcodeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetWechatOffiaccountQrcodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWechatOffiaccountQrcodeLogic {
|
||||
return &GetWechatOffiaccountQrcodeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetWechatOffiaccountQrcodeLogic) GetWechatOffiaccountQrcode(r *http.Request, req *types.OAuthWechatRequest) (resp *types.Response, err error) {
|
||||
ip := utils.GetClientIP(r) // 使用工具函数获取客户端IP
|
||||
key := constant.UserQrcodePrefix + ip
|
||||
|
||||
// 从Redis获取二维码数据
|
||||
qrcode := l.svcCtx.RedisClient.Get(l.ctx, key).Val()
|
||||
if qrcode != "" {
|
||||
data := new(response.ResponseQRCodeCreate)
|
||||
if err = json.Unmarshal([]byte(qrcode), data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response2.SuccessWithData(data.Url), nil
|
||||
}
|
||||
|
||||
// 生成临时二维码
|
||||
data, err := l.svcCtx.WechatOfficial.QRCode.Temporary(l.ctx, req.Client_id, 7*24*3600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 序列化数据并存储到Redis
|
||||
serializedData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = l.svcCtx.RedisClient.Set(l.ctx, key, serializedData, time.Hour*24*7).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response2.SuccessWithData(data.Url), nil
|
||||
}
|
@@ -79,32 +79,22 @@ func (l *PhoneLoginLogic) PhoneLogin(r *http.Request, w http.ResponseWriter, req
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
data, err := HandleUserLogin(user, l.svcCtx, req.AutoLogin, r, w, l.ctx)
|
||||
data, err := HandleLoginJWT(user, l.svcCtx, req.AutoLogin, r, l.ctx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
// 记录用户登录设备
|
||||
if err = GetUserLoginDevice(user.UID, r, l.svcCtx.Ip2Region, l.svcCtx.DB); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.SuccessWithData(data), nil
|
||||
} else {
|
||||
data, err := HandleUserLogin(userInfo, l.svcCtx, req.AutoLogin, r, w, l.ctx)
|
||||
data, err := HandleLoginJWT(userInfo, l.svcCtx, req.AutoLogin, r, l.ctx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
// 记录用户登录设备
|
||||
if err = GetUserLoginDevice(userInfo.UID, r, l.svcCtx.Ip2Region, l.svcCtx.DB); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -0,0 +1,107 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/yitter/idgenerator-go/idgen"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/constant"
|
||||
randomname "schisandra-album-cloud-microservices/app/core/api/common/random_name"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/response"
|
||||
"schisandra-album-cloud-microservices/app/core/api/common/utils"
|
||||
"schisandra-album-cloud-microservices/app/core/api/repository/mysql/model"
|
||||
"strconv"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/core/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type WechatOffiaccountLoginLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewWechatOffiaccountLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatOffiaccountLoginLogic {
|
||||
return &WechatOffiaccountLoginLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *WechatOffiaccountLoginLogic) WechatOffiaccountLogin(r *http.Request, req *types.WechatOffiaccountLoginRequest) (resp *types.Response, err error) {
|
||||
tx := l.svcCtx.DB.Begin()
|
||||
userSocial := l.svcCtx.DB.ScaAuthUserSocial
|
||||
socialUser, err := tx.ScaAuthUserSocial.Where(userSocial.OpenID.Eq(req.Openid), userSocial.Source.Eq(constant.OAuthSourceWechat)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
if socialUser == nil {
|
||||
// 创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
avatar := utils.GenerateAvatar(uidStr)
|
||||
name := randomname.GenerateName()
|
||||
|
||||
addUser := &model.ScaAuthUser{
|
||||
UID: uidStr,
|
||||
Avatar: avatar,
|
||||
Username: req.Openid,
|
||||
Nickname: name,
|
||||
Gender: constant.Male,
|
||||
}
|
||||
err = tx.ScaAuthUser.Create(addUser)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newSocialUser := &model.ScaAuthUserSocial{
|
||||
UserID: uidStr,
|
||||
OpenID: req.Openid,
|
||||
Source: constant.OAuthSourceWechat,
|
||||
}
|
||||
err = tx.ScaAuthUserSocial.Create(newSocialUser)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res, err := l.svcCtx.CasbinEnforcer.AddRoleForUser(uidStr, constant.User); !res || err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := HandleLoginJWT(addUser, l.svcCtx, true, r, l.ctx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.SuccessWithData(data), nil
|
||||
} else {
|
||||
authUser := l.svcCtx.DB.ScaAuthUser
|
||||
|
||||
authUserInfo, err := tx.ScaAuthUser.Where(authUser.UID.Eq(socialUser.UserID)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
data, err := HandleLoginJWT(authUserInfo, l.svcCtx, true, r, l.ctx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.SuccessWithData(data), nil
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user