154 lines
4.4 KiB
Go
154 lines
4.4 KiB
Go
package usecase
|
|
|
|
import (
|
|
"chat/internal/domain/repository"
|
|
"chat/internal/domain/usecase"
|
|
"chat/internal/utils"
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v4"
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
)
|
|
|
|
type authUseCase struct {
|
|
jwtSecret string
|
|
jwtExpire int64
|
|
centrifugoSecret string
|
|
matchmakingRepo repository.MatchmakingRepository
|
|
}
|
|
|
|
// NewAuthUseCase 創建新的認證 UseCase
|
|
func NewAuthUseCase(jwtSecret string, jwtExpire int64, centrifugoSecret string, matchmakingRepo repository.MatchmakingRepository) usecase.AuthUseCase {
|
|
if centrifugoSecret == "" {
|
|
centrifugoSecret = jwtSecret
|
|
}
|
|
|
|
return &authUseCase{
|
|
jwtSecret: jwtSecret,
|
|
jwtExpire: jwtExpire,
|
|
centrifugoSecret: centrifugoSecret,
|
|
matchmakingRepo: matchmakingRepo,
|
|
}
|
|
}
|
|
|
|
// AnonLogin 匿名登入
|
|
func (u *authUseCase) AnonLogin(ctx context.Context, name string) (uid string, token string, centrifugoToken string, expireAt int64, err error) {
|
|
// 生成匿名 UID
|
|
uid = utils.GenerateUID()
|
|
|
|
// 生成 API JWT token
|
|
now := time.Now()
|
|
expireAt = now.Add(time.Duration(u.jwtExpire) * time.Second).Unix()
|
|
|
|
claims := jwt.MapClaims{
|
|
"uid": uid,
|
|
"exp": expireAt,
|
|
"iat": now.Unix(),
|
|
"name": name,
|
|
}
|
|
|
|
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
token, err = jwtToken.SignedString([]byte(u.jwtSecret))
|
|
if err != nil {
|
|
return "", "", "", 0, fmt.Errorf("failed to sign JWT: %w", err)
|
|
}
|
|
|
|
// 匿名登入時還未加入房間,只給予個人頻道的權限
|
|
centrifugoExpireAt := expireAt
|
|
centrifugoClaims := jwt.MapClaims{
|
|
"sub": uid,
|
|
"exp": centrifugoExpireAt,
|
|
"iat": now.Unix(),
|
|
"channels": []string{fmt.Sprintf("user:%s", uid)},
|
|
"name": name,
|
|
}
|
|
|
|
centrifugoJwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, centrifugoClaims)
|
|
centrifugoToken, err = centrifugoJwtToken.SignedString([]byte(u.centrifugoSecret))
|
|
if err != nil {
|
|
return "", "", "", 0, fmt.Errorf("failed to sign Centrifugo JWT: %w", err)
|
|
}
|
|
|
|
logx.Infof("User %s logged in anonymously", uid)
|
|
return uid, token, centrifugoToken, expireAt, nil
|
|
}
|
|
|
|
// RefreshToken 刷新 token
|
|
func (u *authUseCase) RefreshToken(ctx context.Context, oldToken string) (uid string, token string, centrifugoToken string, expireAt int64, err error) {
|
|
// 解析舊 token
|
|
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
|
|
tokenObj, err := parser.Parse(oldToken, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, jwt.ErrSignatureInvalid
|
|
}
|
|
return []byte(u.jwtSecret), nil
|
|
})
|
|
|
|
if err != nil {
|
|
return "", "", "", 0, fmt.Errorf("failed to parse old token: %w", err)
|
|
}
|
|
|
|
claims, ok := tokenObj.Claims.(jwt.MapClaims)
|
|
if !ok {
|
|
return "", "", "", 0, fmt.Errorf("invalid token claims")
|
|
}
|
|
|
|
uid, ok = claims["uid"].(string)
|
|
if !ok || uid == "" {
|
|
return "", "", "", 0, fmt.Errorf("UID not found in token")
|
|
}
|
|
|
|
name, _ := claims["name"].(string)
|
|
|
|
// 檢查使用者當前的房間狀態
|
|
_, roomID, err := u.matchmakingRepo.GetMatchStatus(ctx, uid)
|
|
if err != nil {
|
|
logx.Errorf("Failed to get match status for refresh token: %v", err)
|
|
// 不中斷流程,只是不給房間權限
|
|
}
|
|
|
|
// 生成新的 API JWT token
|
|
now := time.Now()
|
|
expireAt = now.Add(time.Duration(u.jwtExpire) * time.Second).Unix()
|
|
|
|
newClaims := jwt.MapClaims{
|
|
"uid": uid,
|
|
"exp": expireAt,
|
|
"iat": now.Unix(),
|
|
"name": name,
|
|
}
|
|
|
|
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
|
|
token, err = jwtToken.SignedString([]byte(u.jwtSecret))
|
|
if err != nil {
|
|
return "", "", "", 0, fmt.Errorf("failed to sign new JWT: %w", err)
|
|
}
|
|
|
|
// 生成新的 Centrifugo JWT token
|
|
channels := []string{fmt.Sprintf("user:%s", uid)}
|
|
// 如果已經在房間中,添加房間頻道的權限
|
|
if roomID != "" {
|
|
channels = append(channels, fmt.Sprintf("room:%s", roomID))
|
|
}
|
|
|
|
centrifugoExpireAt := expireAt
|
|
centrifugoClaims := jwt.MapClaims{
|
|
"sub": uid,
|
|
"exp": centrifugoExpireAt,
|
|
"iat": now.Unix(),
|
|
"channels": channels,
|
|
"name": name,
|
|
}
|
|
|
|
centrifugoJwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, centrifugoClaims)
|
|
centrifugoToken, err = centrifugoJwtToken.SignedString([]byte(u.centrifugoSecret))
|
|
if err != nil {
|
|
return "", "", "", 0, fmt.Errorf("failed to sign new Centrifugo JWT: %w", err)
|
|
}
|
|
|
|
logx.Infof("User %s refreshed token, room: %s", uid, roomID)
|
|
return uid, token, centrifugoToken, expireAt, nil
|
|
}
|