backend/internal/logic/auth/register_logic.go

218 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package auth
import (
"backend/internal/svc"
"backend/internal/types"
"backend/pkg/library/errs"
"backend/pkg/library/errs/code"
mb "backend/pkg/member/domain/member"
member "backend/pkg/member/domain/usecase"
"backend/pkg/permission/domain/entity"
"backend/pkg/permission/domain/token"
"context"
"time"
"google.golang.org/protobuf/proto"
"github.com/zeromicro/go-zero/core/logx"
)
type RegisterLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
var PrepareFunc map[string]func(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) = map[string]func(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error){
mb.Digimon.ToString(): buildCredentialsData,
mb.Google.ToString(): buildGoogleData,
mb.Line.ToString(): buildLineData,
}
// NewRegisterLogic 註冊新帳號
func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
return &RegisterLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RegisterLogic) Register(req *types.LoginReq) (resp *types.LoginResp, err error) {
// Step 1: 根據平台構建相關資料
var bd buildData
switch req.AuthMethod {
case "credentials":
fn, ok := PrepareFunc[mb.Digimon.ToString()]
if !ok {
return nil, errs.InvalidRangeWithScope(code.CloudEPMember, 0, "failed to get correct credentials method")
}
bd, err = fn(l.ctx, req, l.svcCtx)
if err != nil {
return nil, err
}
case "platform":
fn, ok := PrepareFunc[req.Platform.Provider]
if !ok {
return nil, errs.InvalidRangeWithScope(code.CloudEPMember, 0, "failed to get correct credentials method")
}
bd, err = fn(l.ctx, req, l.svcCtx)
if err != nil {
return nil, err
}
default:
return nil, errs.InvalidFormatWithScope(code.CloudEPMember, "failed to get correct auth method")
}
// Step 2: 建立帳號
if err := l.svcCtx.AccountUC.CreateUserAccount(l.ctx, bd.CreateAccountReq); err != nil {
return nil, err
}
// Step 3: 綁定帳號並獲取 UID
account, err := l.svcCtx.AccountUC.BindAccount(l.ctx, bd.BindingUserReq)
if err != nil {
return nil, err
}
bd.CreateUserInfoRequest.UID = account.UID
// Step 4: 更新使用者資訊
if err := l.svcCtx.AccountUC.BindUserInfo(l.ctx, bd.CreateUserInfoRequest); err != nil {
return nil, err
}
// Step 5: 生成 Token
req.LoginID = bd.CreateAccountReq.LoginID
tk, err := l.generateToken(req, account.UID)
if err != nil {
return nil, err
}
return &types.LoginResp{
UID: account.UID,
AccessToken: tk.AccessToken,
RefreshToken: tk.RefreshToken,
TokenType: tk.TokenType,
}, nil
}
type buildData struct {
CreateAccountReq member.CreateLoginUserRequest
BindingUserReq member.BindingUser
CreateUserInfoRequest member.CreateUserInfoRequest
}
func buildCredentialsData(_ context.Context, req *types.LoginReq, _ *svc.ServiceContext) (buildData, error) {
return buildData{
CreateAccountReq: member.CreateLoginUserRequest{
LoginID: req.LoginID,
Token: req.Credentials.Password,
Platform: mb.Digimon,
},
BindingUserReq: member.BindingUser{
LoginID: req.LoginID,
Type: mb.GetAccountTypeByCode(req.Credentials.AccountType),
},
CreateUserInfoRequest: member.CreateUserInfoRequest{
AlarmCategory: mb.AlarmNoAlert,
UserStatus: mb.AccountStatusUnverified,
PreferredLanguage: mb.LangTW.ToString(),
Currency: mb.CurrencyTWD.ToString(),
},
}, nil
}
func buildGoogleData(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) {
googleToken, err := svc.AccountUC.VerifyGoogleAuthResult(ctx, member.VerifyAuthResultRequest{
Account: req.LoginID,
Token: req.Platform.Token,
})
if err != nil {
return buildData{}, err
}
return buildData{
CreateAccountReq: member.CreateLoginUserRequest{
LoginID: googleToken.Email,
Token: "",
Platform: mb.Google,
},
BindingUserReq: member.BindingUser{
LoginID: req.LoginID,
Type: mb.AccountTypeNone,
},
CreateUserInfoRequest: member.CreateUserInfoRequest{
AvatarURL: proto.String(googleToken.Picture),
FullName: proto.String(googleToken.Name),
Nickname: proto.String(googleToken.Name),
Email: proto.String(googleToken.Email),
AlarmCategory: mb.AlarmNoAlert,
UserStatus: mb.AccountStatusUnverified,
PreferredLanguage: mb.LangTW.ToString(),
Currency: mb.CurrencyTWD.ToString(),
},
}, nil
}
func buildLineData(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) {
lineAccessToken, err := svc.AccountUC.LineCodeToAccessToken(ctx, req.LoginID)
if err != nil {
return buildData{}, err
}
userInfo, err := svc.AccountUC.LineGetProfileByAccessToken(ctx, lineAccessToken.AccessToken)
if err != nil {
return buildData{}, err
}
return buildData{
CreateAccountReq: member.CreateLoginUserRequest{
LoginID: userInfo.UserID,
Token: "",
Platform: mb.Line,
},
BindingUserReq: member.BindingUser{
LoginID: userInfo.UserID,
Type: mb.AccountTypeNone,
},
CreateUserInfoRequest: member.CreateUserInfoRequest{
AvatarURL: proto.String(userInfo.PictureURL),
FullName: proto.String(userInfo.DisplayName),
Nickname: proto.String(userInfo.DisplayName),
AlarmCategory: mb.AlarmNoAlert,
UserStatus: mb.AccountStatusUnverified,
PreferredLanguage: mb.LangTW.ToString(),
Currency: mb.CurrencyTWD.ToString(),
},
}, nil
}
// 生成 Token
func (l *RegisterLogic) generateToken(req *types.LoginReq, uid string) (entity.TokenResp, error) {
// scope role 要修改refresh tl
role := "user"
tk, err := l.svcCtx.TokenUC.NewToken(l.ctx, entity.AuthorizationReq{
GrantType: token.ClientCredentials.ToString(),
DeviceID: uid, // TODO 沒傳暫時先用UID 替代
Scope: "gateway",
IsRefreshToken: true,
Expires: time.Now().UTC().Add(l.svcCtx.Config.Token.AccessTokenExpiry).Unix(),
Data: map[string]string{
"uid": uid,
"role": role,
},
Role: role,
Account: req.LoginID,
})
if err != nil {
return entity.TokenResp{}, err
}
return entity.TokenResp{
AccessToken: tk.AccessToken,
TokenType: tk.TokenType,
ExpiresIn: tk.ExpiresIn,
RefreshToken: tk.RefreshToken,
}, nil
}