169 lines
4.5 KiB
Go
169 lines
4.5 KiB
Go
package member
|
|
|
|
import (
|
|
"biz-member-gateway/internal/domain"
|
|
bizDomain "biz-member-gateway/internal/domain"
|
|
"biz-member-gateway/internal/svc"
|
|
"biz-member-gateway/internal/types"
|
|
"context"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.30cm.net/digimon/app-cloudep-member-server/pkg/domain/member"
|
|
memberUC "code.30cm.net/digimon/app-cloudep-member-server/pkg/domain/usecase"
|
|
"code.30cm.net/digimon/library-go/errs"
|
|
memberProto "code.30cm.net/digimon/proto-all/pkg/member"
|
|
permissionProto "code.30cm.net/digimon/proto-all/pkg/permission"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
)
|
|
|
|
type LoginLogic struct {
|
|
logx.Logger
|
|
ctx context.Context
|
|
svcCtx *svc.ServiceContext
|
|
}
|
|
|
|
// NewLoginLogic 登入
|
|
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
|
|
return &LoginLogic{
|
|
Logger: logx.WithContext(ctx),
|
|
ctx: ctx,
|
|
svcCtx: svcCtx,
|
|
}
|
|
}
|
|
|
|
func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginTokenResp, err error) {
|
|
var result memberUC.VerifyAuthResultResponse
|
|
// Step 1 驗證進來的 Token
|
|
platform := member.GetPlatformByPlatformCode(req.Platform)
|
|
|
|
switch platform {
|
|
case member.Digimon:
|
|
switch member.GetAccountTypeByCode(req.AccountType) {
|
|
case member.AccountTypePhone:
|
|
phone, isPhone := normalizeTaiwanMobile(req.Account)
|
|
if !isPhone {
|
|
return nil, errs.InvalidFormat("phone number is invalid")
|
|
}
|
|
req.Account = phone
|
|
case member.AccountTypeMail:
|
|
if !isValidEmail(req.Account) {
|
|
return nil, errs.InvalidFormat("email is invalid")
|
|
}
|
|
}
|
|
|
|
// 原始平台驗證
|
|
res, err := l.svcCtx.MemberRPC.VerifyPlatformAuthResult(l.ctx, &memberProto.VerifyAuthResultReq{
|
|
Account: proto.String(req.Account),
|
|
Token: req.Token,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result.Status = res.Status
|
|
case member.Google:
|
|
// 原始平台驗證
|
|
_, err := l.svcCtx.MemberRPC.VerifyGoogleAuthResult(l.ctx, &memberProto.VerifyAuthResultReq{
|
|
Account: proto.String(req.Account),
|
|
Token: req.Token,
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result.Status = true
|
|
case member.Line:
|
|
// 原始平台驗證
|
|
accessToken, err := l.svcCtx.MemberRPC.LineCodeToAccessToken(l.ctx, &memberProto.LineGetTokenReq{
|
|
Code: req.Account,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 換資料
|
|
userInfo, err := l.svcCtx.MemberRPC.LineGetProfileByAccessToken(l.ctx, &memberProto.LineGetUserInfoReq{
|
|
Token: accessToken.Token,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result.Status = true
|
|
req.Account = userInfo.UserId
|
|
case member.PlatformNone:
|
|
default:
|
|
return nil, errs.InvalidFormat("invalid platform")
|
|
}
|
|
|
|
if !result.Status {
|
|
return nil, errs.Unauthorized("failed to validate password ")
|
|
}
|
|
|
|
account, err := l.svcCtx.MemberRPC.GetUIDByAccount(l.ctx, &memberProto.GetUIDByAccountReq{
|
|
Account: req.Account,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
credentials := "client_credentials"
|
|
// TODO 去拿這個使用者Role
|
|
role := bizDomain.DefaultRole
|
|
|
|
t, err := l.svcCtx.TokenRPC.NewToken(l.ctx, &permissionProto.AuthorizationReq{
|
|
GrantType: credentials,
|
|
DeviceId: req.DeviceID,
|
|
Scope: role,
|
|
IsRefreshToken: true,
|
|
Account: req.Account,
|
|
Uid: account.GetUid(),
|
|
Expires: proto.Int64(time.Now().UTC().Add(l.svcCtx.Config.Token.Expired).UnixNano()), // 指定到期的時間
|
|
RefreshExpire: proto.Int64(time.Now().UTC().Add(l.svcCtx.Config.Token.RefreshExpired).UnixNano()), // 指定到期的時間
|
|
Data: map[string]string{},
|
|
Role: role,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.LoginTokenResp{
|
|
UID: account.GetUid(),
|
|
AccessToken: t.AccessToken,
|
|
RefreshToken: t.RefreshToken,
|
|
TokenType: domain.TokenTypeBearer,
|
|
}, nil
|
|
}
|
|
|
|
// 標準化號碼並驗證是否為合法台灣手機號碼
|
|
func normalizeTaiwanMobile(phone string) (string, bool) {
|
|
// 移除空格
|
|
phone = strings.ReplaceAll(phone, " ", "")
|
|
|
|
// 移除 "+886" 並將剩餘部分標準化
|
|
if strings.HasPrefix(phone, "+886") {
|
|
phone = strings.TrimPrefix(phone, "+886")
|
|
if !strings.HasPrefix(phone, "0") {
|
|
phone = "0" + phone
|
|
}
|
|
}
|
|
|
|
// 正則表達式驗證標準化後的號碼
|
|
regex := regexp.MustCompile(`^(09\d{8})$`)
|
|
if regex.MatchString(phone) {
|
|
return phone, true
|
|
}
|
|
|
|
return "", false
|
|
}
|
|
|
|
// 驗證 Email 格式的函數
|
|
func isValidEmail(email string) bool {
|
|
// 定義正則表達式
|
|
regex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
|
|
|
|
return regex.MatchString(email)
|
|
}
|