Files
mayfly-go/server/internal/auth/api/common.go

126 lines
3.8 KiB
Go
Raw Normal View History

2023-07-22 20:51:46 +08:00
package api
import (
"context"
2023-07-22 20:51:46 +08:00
"fmt"
"mayfly-go/internal/auth/config"
2024-11-20 22:43:53 +08:00
"mayfly-go/internal/auth/imsg"
2024-12-08 13:04:23 +08:00
"mayfly-go/internal/auth/pkg/otp"
msgdto "mayfly-go/internal/msg/application/dto"
"mayfly-go/internal/pkg/event"
2023-07-22 20:51:46 +08:00
sysapp "mayfly-go/internal/sys/application"
sysentity "mayfly-go/internal/sys/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/global"
2023-07-22 20:51:46 +08:00
"mayfly-go/pkg/req"
2023-10-12 12:14:56 +08:00
"mayfly-go/pkg/utils/collx"
2023-07-22 20:51:46 +08:00
"mayfly-go/pkg/utils/netx"
"mayfly-go/pkg/utils/stringx"
"mayfly-go/pkg/utils/timex"
"time"
)
const (
OtpStatusNone = -1 // 未启用otp校验
OtpStatusReg = 1 // 用户otp secret已注册
OtpStatusNoReg = 2 // 用户otp secret未注册
)
// 最后的登录校验共用。校验通过返回登录成功响应结果map
2024-11-20 22:43:53 +08:00
func LastLoginCheck(ctx context.Context, account *sysentity.Account, accountLoginSecurity *config.AccountLoginSecurity, loginIp string) map[string]any {
biz.IsTrueI(ctx, account.IsEnable(), imsg.ErrAccountNotAvailable)
2023-07-22 20:51:46 +08:00
username := account.Username
2023-10-12 12:14:56 +08:00
res := collx.M{
2023-07-22 20:51:46 +08:00
"name": account.Name,
"username": username,
"lastLoginTime": account.LastLoginTime,
"lastLoginIp": account.LastLoginIp,
}
// 默认为不校验otp
otpStatus := OtpStatusNone
// 访问系统使用的token
accessToken, refreshToken, err := req.CreateToken(account.Id, username)
2024-11-20 22:43:53 +08:00
biz.ErrIsNilAppendErr(err, "token create failed: %s")
2023-07-22 20:51:46 +08:00
// 若系统配置中设置开启otp双因素校验则进行otp校验
if accountLoginSecurity.UseOtp {
otpInfo, otpurl, otpToken := useOtp(account, accountLoginSecurity.OtpIssuer, accessToken, refreshToken)
2023-07-22 20:51:46 +08:00
otpStatus = otpInfo.OptStatus
if otpurl != "" {
res["otpUrl"] = otpurl
}
accessToken = otpToken
} else {
res["refresh_token"] = refreshToken
2023-07-22 20:51:46 +08:00
// 不进行otp二次校验则直接返回accessToken
// 保存登录消息
2024-11-20 22:43:53 +08:00
go saveLogin(ctx, account, loginIp)
2023-07-22 20:51:46 +08:00
}
// 赋值otp状态
res["otp"] = otpStatus
res["token"] = accessToken
return res
}
func useOtp(account *sysentity.Account, otpIssuer, accessToken string, refreshToken string) (*OtpVerifyInfo, string, string) {
biz.ErrIsNil(account.OtpSecretDecrypt())
2023-07-22 20:51:46 +08:00
otpSecret := account.OtpSecret
// 修改状态为已注册
otpStatus := OtpStatusReg
otpUrl := ""
// 该token用于otp双因素校验
token := stringx.Rand(32)
// 未注册otp secret或重置了秘钥
if otpSecret == "" || otpSecret == "-" {
otpStatus = OtpStatusNoReg
key, err := otp.NewTOTP(otp.GenerateOpts{
AccountName: account.Username,
Issuer: otpIssuer,
})
2024-11-20 22:43:53 +08:00
biz.ErrIsNilAppendErr(err, "otp generate failed: %s")
2023-07-22 20:51:46 +08:00
otpUrl = key.URL()
otpSecret = key.Secret()
}
// 缓存otpInfo, 只有双因素校验通过才可返回真正的token
2023-07-22 20:51:46 +08:00
otpInfo := &OtpVerifyInfo{
AccountId: account.Id,
Username: account.Username,
OptStatus: otpStatus,
OtpSecret: otpSecret,
AccessToken: accessToken,
RefreshToken: refreshToken,
2023-07-22 20:51:46 +08:00
}
2025-04-23 20:36:32 +08:00
cache.Set(fmt.Sprintf("otp:token:%s", token), otpInfo, time.Minute*time.Duration(3))
2023-07-22 20:51:46 +08:00
return otpInfo, otpUrl, token
}
// 获取ip与归属地信息
func getIpAndRegion(rc *req.Ctx) string {
2024-02-25 12:46:18 +08:00
clientIp := rc.ClientIP()
2023-07-22 20:51:46 +08:00
return fmt.Sprintf("%s %s", clientIp, netx.Ip2Region(clientIp))
}
// 保存更新账号登录信息
2024-11-20 22:43:53 +08:00
func saveLogin(ctx context.Context, account *sysentity.Account, ip string) {
2023-07-22 20:51:46 +08:00
// 更新账号最后登录时间
now := time.Now()
updateAccount := &sysentity.Account{LastLoginTime: &now}
updateAccount.Id = account.Id
updateAccount.LastLoginIp = ip
// 偷懒为了方便直接获取accountApp
biz.ErrIsNil(sysapp.GetAccountApp().Update(context.TODO(), updateAccount))
2023-07-22 20:51:46 +08:00
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, &msgdto.MsgTmplSendEvent{
TmplChannel: msgdto.MsgTmplLogin,
Params: collx.M{
"ip": ip,
"time": timex.DefaultFormat(now),
},
ReceiverIds: []uint64{account.Id},
})
2023-07-22 20:51:46 +08:00
}