2024-08-24 07:14:58 +00:00
|
|
|
|
package tokenservicelogic
|
|
|
|
|
|
|
|
|
|
import (
|
2024-08-24 14:40:09 +00:00
|
|
|
|
"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"
|
2024-08-24 07:14:58 +00:00
|
|
|
|
"context"
|
2024-08-24 14:40:09 +00:00
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"time"
|
2024-08-24 07:14:58 +00:00
|
|
|
|
|
|
|
|
|
"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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-24 14:40:09 +00:00
|
|
|
|
// 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"`
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-24 07:14:58 +00:00
|
|
|
|
// NewToken 建立一個新的 Token,例如:AccessToken
|
|
|
|
|
func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.TokenResp, error) {
|
2024-08-24 14:40:09 +00:00
|
|
|
|
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)
|
|
|
|
|
}
|
2024-08-24 07:14:58 +00:00
|
|
|
|
|
2024-08-24 14:40:09 +00:00
|
|
|
|
return &token, nil
|
2024-08-24 07:14:58 +00:00
|
|
|
|
}
|