139 lines
3.8 KiB
Go
139 lines
3.8 KiB
Go
package tokenservicelogic
|
||
|
||
import (
|
||
"app-cloudep-permission-server/internal/config"
|
||
"app-cloudep-permission-server/internal/domain"
|
||
"app-cloudep-permission-server/internal/entity"
|
||
ers "code.30cm.net/digimon/library-go/errors"
|
||
"context"
|
||
"github.com/google/uuid"
|
||
"time"
|
||
|
||
"app-cloudep-permission-server/gen_result/pb/permission"
|
||
"app-cloudep-permission-server/internal/svc"
|
||
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
)
|
||
|
||
type NewTokenLogic struct {
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
logx.Logger
|
||
}
|
||
|
||
func NewNewTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewTokenLogic {
|
||
return &NewTokenLogic{
|
||
ctx: ctx,
|
||
svcCtx: svcCtx,
|
||
Logger: logx.WithContext(ctx),
|
||
}
|
||
}
|
||
|
||
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
|
||
type authorizationReq struct {
|
||
GrantType domain.GrantType `json:"grant_type" validate:"required,oneof=password client_credentials refresh_token"`
|
||
DeviceID string `json:"device_id"`
|
||
Scope string `json:"scope" validate:"required"`
|
||
Data map[string]string `json:"data"`
|
||
Expires int `json:"expires"`
|
||
IsRefreshToken bool `json:"is_refresh_token"`
|
||
}
|
||
|
||
// NewToken 建立一個新的 Token,例如:AccessToken
|
||
func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
||
data := authorizationReq{
|
||
GrantType: domain.GrantType(in.GetGrantType()),
|
||
Scope: in.GetScope(),
|
||
DeviceID: in.GetDeviceId(),
|
||
Data: in.GetData(),
|
||
Expires: int(in.GetExpires()),
|
||
IsRefreshToken: in.GetIsRefreshToken(),
|
||
}
|
||
// 驗證所需
|
||
if err := l.svcCtx.Validate.ValidateAll(&data); err != nil {
|
||
return nil, ers.InvalidFormat(err.Error())
|
||
}
|
||
token, err := newToken(data, l.svcCtx.Config)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
err = l.svcCtx.TokenRedisRepo.Create(l.ctx, *token)
|
||
if err != nil {
|
||
logx.WithCallerSkip(1).WithFields(
|
||
logx.Field("func", "TokenRedisRepo.Create"),
|
||
logx.Field("token", token),
|
||
).Error(err.Error())
|
||
return nil, err
|
||
}
|
||
|
||
return &permission.TokenResp{
|
||
AccessToken: token.AccessToken,
|
||
TokenType: domain.TokenTypeBearer,
|
||
ExpiresIn: int32(token.ExpiresIn),
|
||
RefreshToken: token.RefreshToken,
|
||
}, nil
|
||
}
|
||
|
||
func newToken(authReq authorizationReq, cfg config.Config) (*entity.Token, error) {
|
||
// 準備建立 Token 所需
|
||
now := time.Now().UTC()
|
||
expires := authReq.Expires
|
||
refreshExpires := authReq.Expires
|
||
if expires <= 0 {
|
||
// 將時間加上 300 秒
|
||
sec := time.Duration(cfg.Token.Expired.Seconds()) * time.Second
|
||
newTime := now.Add(sec)
|
||
// 獲取 Unix 時間戳
|
||
timestamp := newTime.Unix()
|
||
expires = int(timestamp)
|
||
refreshExpires = expires
|
||
}
|
||
|
||
// 如果這是一個 Refresh Token 過期時間要比普通的Token 長
|
||
if authReq.IsRefreshToken {
|
||
// 將時間加上 300 秒
|
||
sec := time.Duration(cfg.Token.RefreshExpires.Seconds()) * time.Second
|
||
newTime := now.Add(sec)
|
||
// 獲取 Unix 時間戳
|
||
timestamp := newTime.Unix()
|
||
refreshExpires = int(timestamp)
|
||
}
|
||
|
||
token := entity.Token{
|
||
ID: uuid.Must(uuid.NewRandom()).String(),
|
||
DeviceID: authReq.DeviceID,
|
||
ExpiresIn: expires,
|
||
RefreshExpiresIn: refreshExpires,
|
||
AccessCreateAt: now,
|
||
RefreshCreateAt: now,
|
||
}
|
||
|
||
claims := claims(authReq.Data)
|
||
claims.SetRole(domain.DefaultRole)
|
||
claims.SetID(token.ID)
|
||
claims.SetScope(authReq.Scope)
|
||
|
||
token.UID = claims.UID()
|
||
|
||
if authReq.DeviceID != "" {
|
||
claims.SetDeviceID(authReq.DeviceID)
|
||
}
|
||
|
||
var err error
|
||
token.AccessToken, err = generateAccessTokenFunc(token, claims, cfg.Token.Secret)
|
||
if err != nil {
|
||
logx.WithCallerSkip(1).WithFields(
|
||
logx.Field("func", "generateAccessTokenFunc"),
|
||
logx.Field("claims", claims),
|
||
).Error(err.Error())
|
||
return nil, err
|
||
}
|
||
|
||
if authReq.IsRefreshToken {
|
||
token.RefreshToken = generateRefreshTokenFunc(token.AccessToken)
|
||
}
|
||
|
||
return &token, nil
|
||
}
|