mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-09 12:00:25 +08:00
实现用户系统手机号码绑定和登录(商业版)
This commit is contained in:
@@ -428,6 +428,20 @@ func (this *UserDAO) CheckUserEmailPassword(tx *dbs.Tx, verifiedEmail string, en
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserMobilePassword 检查邮箱+密码
|
||||||
|
func (this *UserDAO) CheckUserMobilePassword(tx *dbs.Tx, verifiedEmail string, encryptedPassword string) (int64, error) {
|
||||||
|
if len(verifiedEmail) == 0 || len(encryptedPassword) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
Attr("verifiedMobile", verifiedEmail).
|
||||||
|
Attr("password", encryptedPassword).
|
||||||
|
Attr("state", UserStateEnabled).
|
||||||
|
Attr("isOn", true).
|
||||||
|
ResultPk().
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserClusterId 查找用户所在集群
|
// FindUserClusterId 查找用户所在集群
|
||||||
func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error) {
|
func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
@@ -663,7 +677,7 @@ func (this *UserDAO) RenewUserServersState(tx *dbs.Tx, userId int64) (bool, erro
|
|||||||
// FindUserIdWithVerifiedEmail 使用验证后Email查找用户ID
|
// FindUserIdWithVerifiedEmail 使用验证后Email查找用户ID
|
||||||
func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail string) (int64, error) {
|
func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail string) (int64, error) {
|
||||||
if len(verifiedEmail) == 0 {
|
if len(verifiedEmail) == 0 {
|
||||||
|
return 0, nil
|
||||||
}
|
}
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
ResultPk().
|
ResultPk().
|
||||||
@@ -672,6 +686,18 @@ func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail strin
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindUserIdWithVerifiedMobile 使用验证后手机号码查找用户ID
|
||||||
|
func (this *UserDAO) FindUserIdWithVerifiedMobile(tx *dbs.Tx, verifiedMobile string) (int64, error) {
|
||||||
|
if len(verifiedMobile) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
ResultPk().
|
||||||
|
State(UserStateEnabled).
|
||||||
|
Attr("verifiedMobile", verifiedMobile).
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateUserVerifiedEmail 修改已激活邮箱
|
// UpdateUserVerifiedEmail 修改已激活邮箱
|
||||||
func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedEmail string) error {
|
func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedEmail string) error {
|
||||||
if userId <= 0 {
|
if userId <= 0 {
|
||||||
@@ -684,6 +710,18 @@ func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedE
|
|||||||
UpdateQuickly()
|
UpdateQuickly()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateUserVerifiedMobile 修改已激活手机号码
|
||||||
|
func (this *UserDAO) UpdateUserVerifiedMobile(tx *dbs.Tx, userId int64, verifiedMobile string) error {
|
||||||
|
if userId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(userId).
|
||||||
|
Set("verifiedMobile", verifiedMobile).
|
||||||
|
Set("mobileIsVerified", true).
|
||||||
|
UpdateQuickly()
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserBandwidthAlgoForView 获取用户浏览用的带宽算法
|
// FindUserBandwidthAlgoForView 获取用户浏览用的带宽算法
|
||||||
func (this *UserDAO) FindUserBandwidthAlgoForView(tx *dbs.Tx, userId int64, uiConfig *systemconfigs.UserUIConfig) (bandwidthAlgo string, err error) {
|
func (this *UserDAO) FindUserBandwidthAlgoForView(tx *dbs.Tx, userId int64, uiConfig *systemconfigs.UserUIConfig) (bandwidthAlgo string, err error) {
|
||||||
bandwidthAlgo, err = this.Query(tx).
|
bandwidthAlgo, err = this.Query(tx).
|
||||||
|
|||||||
28
internal/db/models/user_mobile_verification_dao.go
Normal file
28
internal/db/models/user_mobile_verification_dao.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserMobileVerificationDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserMobileVerificationDAO() *UserMobileVerificationDAO {
|
||||||
|
return dbs.NewDAO(&UserMobileVerificationDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserMobileVerifications",
|
||||||
|
Model: new(UserMobileVerification),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserMobileVerificationDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserMobileVerificationDAO *UserMobileVerificationDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserMobileVerificationDAO = NewUserMobileVerificationDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
6
internal/db/models/user_mobile_verification_dao_test.go
Normal file
6
internal/db/models/user_mobile_verification_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
41
internal/db/models/user_mobile_verification_model.go
Normal file
41
internal/db/models/user_mobile_verification_model.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserMobileVerificationField_Id dbs.FieldName = "id" // ID
|
||||||
|
UserMobileVerificationField_Mobile dbs.FieldName = "mobile" // 手机号码
|
||||||
|
UserMobileVerificationField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
UserMobileVerificationField_Code dbs.FieldName = "code" // 激活码
|
||||||
|
UserMobileVerificationField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
UserMobileVerificationField_IsSent dbs.FieldName = "isSent" // 是否已发送
|
||||||
|
UserMobileVerificationField_IsVerified dbs.FieldName = "isVerified" // 是否已激活
|
||||||
|
UserMobileVerificationField_Day dbs.FieldName = "day" // YYYYMMDD
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserMobileVerification 邮箱激活邮件队列
|
||||||
|
type UserMobileVerification struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
Mobile string `field:"mobile"` // 手机号码
|
||||||
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
|
Code string `field:"code"` // 激活码
|
||||||
|
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||||
|
IsSent bool `field:"isSent"` // 是否已发送
|
||||||
|
IsVerified bool `field:"isVerified"` // 是否已激活
|
||||||
|
Day string `field:"day"` // YYYYMMDD
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserMobileVerificationOperator struct {
|
||||||
|
Id any // ID
|
||||||
|
Mobile any // 手机号码
|
||||||
|
UserId any // 用户ID
|
||||||
|
Code any // 激活码
|
||||||
|
CreatedAt any // 创建时间
|
||||||
|
IsSent any // 是否已发送
|
||||||
|
IsVerified any // 是否已激活
|
||||||
|
Day any // YYYYMMDD
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserMobileVerificationOperator() *UserMobileVerificationOperator {
|
||||||
|
return &UserMobileVerificationOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/user_mobile_verification_model_ext.go
Normal file
1
internal/db/models/user_mobile_verification_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
@@ -10,6 +10,7 @@ const (
|
|||||||
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
|
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
|
||||||
UserField_Mobile dbs.FieldName = "mobile" // 手机号
|
UserField_Mobile dbs.FieldName = "mobile" // 手机号
|
||||||
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
|
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
|
||||||
|
UserField_MobileIsVerified dbs.FieldName = "mobileIsVerified" // 手机号是否已验证
|
||||||
UserField_Tel dbs.FieldName = "tel" // 联系电话
|
UserField_Tel dbs.FieldName = "tel" // 联系电话
|
||||||
UserField_Remark dbs.FieldName = "remark" // 备注
|
UserField_Remark dbs.FieldName = "remark" // 备注
|
||||||
UserField_Email dbs.FieldName = "email" // 邮箱地址
|
UserField_Email dbs.FieldName = "email" // 邮箱地址
|
||||||
@@ -47,6 +48,7 @@ type User struct {
|
|||||||
Fullname string `field:"fullname"` // 真实姓名
|
Fullname string `field:"fullname"` // 真实姓名
|
||||||
Mobile string `field:"mobile"` // 手机号
|
Mobile string `field:"mobile"` // 手机号
|
||||||
VerifiedMobile string `field:"verifiedMobile"` // 已验证手机号
|
VerifiedMobile string `field:"verifiedMobile"` // 已验证手机号
|
||||||
|
MobileIsVerified uint8 `field:"mobileIsVerified"` // 手机号是否已验证
|
||||||
Tel string `field:"tel"` // 联系电话
|
Tel string `field:"tel"` // 联系电话
|
||||||
Remark string `field:"remark"` // 备注
|
Remark string `field:"remark"` // 备注
|
||||||
Email string `field:"email"` // 邮箱地址
|
Email string `field:"email"` // 邮箱地址
|
||||||
@@ -83,6 +85,7 @@ type UserOperator struct {
|
|||||||
Fullname any // 真实姓名
|
Fullname any // 真实姓名
|
||||||
Mobile any // 手机号
|
Mobile any // 手机号
|
||||||
VerifiedMobile any // 已验证手机号
|
VerifiedMobile any // 已验证手机号
|
||||||
|
MobileIsVerified any // 手机号是否已验证
|
||||||
Tel any // 联系电话
|
Tel any // 联系电话
|
||||||
Remark any // 备注
|
Remark any // 备注
|
||||||
Email any // 邮箱地址
|
Email any // 邮箱地址
|
||||||
|
|||||||
@@ -241,7 +241,8 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.FindEnabledUserResponse{User: &pb.User{
|
return &pb.FindEnabledUserResponse{
|
||||||
|
User: &pb.User{
|
||||||
Id: int64(user.Id),
|
Id: int64(user.Id),
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
Fullname: user.Fullname,
|
Fullname: user.Fullname,
|
||||||
@@ -249,6 +250,7 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
|
|||||||
Tel: user.Tel,
|
Tel: user.Tel,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
VerifiedEmail: user.VerifiedEmail,
|
VerifiedEmail: user.VerifiedEmail,
|
||||||
|
VerifiedMobile: user.VerifiedMobile,
|
||||||
Remark: user.Remark,
|
Remark: user.Remark,
|
||||||
IsOn: user.IsOn,
|
IsOn: user.IsOn,
|
||||||
CreatedAt: int64(user.CreatedAt),
|
CreatedAt: int64(user.CreatedAt),
|
||||||
@@ -262,7 +264,8 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
|
|||||||
BandwidthAlgo: user.BandwidthAlgo,
|
BandwidthAlgo: user.BandwidthAlgo,
|
||||||
OtpLogin: pbOtpAuth,
|
OtpLogin: pbOtpAuth,
|
||||||
Lang: user.Lang,
|
Lang: user.Lang,
|
||||||
}}, nil
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckUserUsername 检查用户名是否存在
|
// CheckUserUsername 检查用户名是否存在
|
||||||
@@ -312,12 +315,15 @@ func (this *UserService) LoginUser(ctx context.Context, req *pb.LoginUserRequest
|
|||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
// 邮箱登录
|
// 邮箱登录
|
||||||
|
var registerConfig *userconfigs.UserRegisterConfig
|
||||||
if strings.Contains(req.Username, "@") {
|
if strings.Contains(req.Username, "@") {
|
||||||
// 是否允许
|
// 是否允许
|
||||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
if registerConfig == nil {
|
||||||
|
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if registerConfig != nil && registerConfig.EmailVerification.CanLogin {
|
if registerConfig != nil && registerConfig.EmailVerification.CanLogin {
|
||||||
userId, err := models.SharedUserDAO.CheckUserEmailPassword(tx, req.Username, req.Password)
|
userId, err := models.SharedUserDAO.CheckUserEmailPassword(tx, req.Username, req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -332,6 +338,29 @@ func (this *UserService) LoginUser(ctx context.Context, req *pb.LoginUserRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手机号登录
|
||||||
|
if utils.IsValidMobile(req.Username) {
|
||||||
|
// 是否允许
|
||||||
|
if registerConfig == nil {
|
||||||
|
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if registerConfig != nil && registerConfig.MobileVerification.CanLogin {
|
||||||
|
userId, err := models.SharedUserDAO.CheckUserMobilePassword(tx, req.Username, req.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userId > 0 {
|
||||||
|
return &pb.LoginUserResponse{
|
||||||
|
UserId: userId,
|
||||||
|
IsOk: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 用户名登录
|
// 用户名登录
|
||||||
userId, err := models.SharedUserDAO.CheckUserPassword(tx, req.Username, req.Password)
|
userId, err := models.SharedUserDAO.CheckUserPassword(tx, req.Username, req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -840,6 +869,28 @@ func (this *UserService) CheckUserEmail(ctx context.Context, req *pb.CheckUserEm
|
|||||||
return &pb.CheckUserEmailResponse{Exists: false}, nil
|
return &pb.CheckUserEmailResponse{Exists: false}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserMobile 检查手机号码是否被使用
|
||||||
|
func (this *UserService) CheckUserMobile(ctx context.Context, req *pb.CheckUserMobileRequest) (*pb.CheckUserMobileResponse, error) {
|
||||||
|
userId, err := this.ValidateUserNode(ctx, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Mobile) == 0 {
|
||||||
|
return nil, errors.New("'mobile' required")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
mobileOwnerUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedMobile(tx, req.Mobile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if mobileOwnerUserId > 0 && userId != mobileOwnerUserId {
|
||||||
|
return &pb.CheckUserMobileResponse{Exists: true}, nil
|
||||||
|
}
|
||||||
|
return &pb.CheckUserMobileResponse{Exists: false}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserVerifiedEmailWithUsername 根据用户名查询用户绑定的邮箱
|
// FindUserVerifiedEmailWithUsername 根据用户名查询用户绑定的邮箱
|
||||||
func (this *UserService) FindUserVerifiedEmailWithUsername(ctx context.Context, req *pb.FindUserVerifiedEmailWithUsernameRequest) (*pb.FindUserVerifiedEmailWithUsernameResponse, error) {
|
func (this *UserService) FindUserVerifiedEmailWithUsername(ctx context.Context, req *pb.FindUserVerifiedEmailWithUsernameRequest) (*pb.FindUserVerifiedEmailWithUsernameResponse, error) {
|
||||||
_, err := this.ValidateUserNode(ctx, false)
|
_, err := this.ValidateUserNode(ctx, false)
|
||||||
|
|||||||
12
internal/utils/mobile.go
Normal file
12
internal/utils/mobile.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
var mobileRegex = regexp.MustCompile(`^1\d{10}$`)
|
||||||
|
|
||||||
|
// IsValidMobile validate mobile number
|
||||||
|
func IsValidMobile(mobile string) bool {
|
||||||
|
return mobileRegex.MatchString(mobile)
|
||||||
|
}
|
||||||
17
internal/utils/mobile_test.go
Normal file
17
internal/utils/mobile_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsValidMobile(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
a.IsFalse(utils.IsValidMobile("138"))
|
||||||
|
a.IsFalse(utils.IsValidMobile("1382222"))
|
||||||
|
a.IsFalse(utils.IsValidMobile("1381234567890"))
|
||||||
|
a.IsTrue(utils.IsValidMobile("13812345678"))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user